主窗体、QFile、编码转换、事件、禁止输入特殊字符

主窗体

部件构成

菜单栏、工具栏、主窗体、状态栏。

UI 编辑器设计主窗体

主窗体的基类要选择 QMainWindow。
在这里插入图片描述

💡 简易记事本的实现(part 1)

在这里插入图片描述
“Ctrl + F” 的功能 ——> (&F)
“Ctrl + E” 的功能 ——> (&E)
“Ctrl + O” 的功能 ——> (&O)
“Ctrl + V” 的功能 ——> (&V)
“Ctrl + H” 的功能 ——> (&H)

菜单栏

当 Action编辑器 没有在界面中显示时,右击即可。
在这里插入图片描述
在这里插入图片描述
右击 ——> 新建,亦可。

工具栏(图标)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
注意,工具栏在菜单栏下方。

主窗体

在这里插入图片描述

完善菜单栏:
在这里插入图片描述

mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    this->setWindowTitle("新建文本文档 - txt");
    this->setWindowIcon(QIcon("://notepad.png"));
}

MainWindow::~MainWindow()
{
    delete ui;
}

Functions

状态栏显示提示信息

设置显示的时长,时间单位:ms。

void showMessage(const QString & message, int timeout = 0);

设置标题栏的标题、图标

void setWindowTitle(const QString &);  			// 设置标题栏的标题
void setWindowIcon(const QIcon & icon);  		// 设置标题栏的图标

设置图标然后运行,如果不能正常显示,不用理会,是系统的问题。

QFile

继承关系

QObject – QIODevice – QFileDevice – QFile
QIODevice:QT 对输入输出设备的抽象,提供了操作设备的一系列接口。

接口

QFile(const QString &name);  	// 使用文件名构造一个 QFile 对象,文件名可以包含路径和文件名
    
void	setFileName(const QString & name);  // 如果构造没指定,也可以通过这个接口指定一下
bool	exists(); 							// 判断文件是否存在
bool 	open(OpenMode mode); 				// 继承自 QIODevice,
	OpenMode 取值:
		QIODevice::ReadOnly
		QIODevice::WriteOnly
		QIODevice::ReadWrite
		...
		
bool 	atEnd();  					// 到达文件尾部
bool	remove();  					// 删除文件
bool	rename(const QString & newName);	  // 重命名文件
qint64	read(char * data, qint64 maxSize);
QByteArray	read(qint64 maxSize);  	// 读取最大maxSize字节,并返回一个QByteArray
QByteArray	readAll();  			// 读取文件中所有数据,并返回一个QByteArray

qint64	write(const char * data, qint64 maxSize);
qint64	write(const QByteArray & byteArray);

qint64	pos() const;  				// 得到当前读写指针的位置
bool 	seek(qint64 pos);  			// 重新设置读写指针位置

bool QFileDevice::resize(qint64 sz); 	// 重设文件大小,可用于清空文件,比如 resize(0) 

qint64 size() const;				// 获取文件大小

💡 简易记事本的实现(part 2)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QtWidgets>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_action_O_triggered();

    void on_action_S_triggered();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    this->setWindowTitle("新建文本文档 - txt");
    this->setWindowIcon(QIcon("://notepad.png"));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_action_O_triggered()
{
    ui->statusBar->showMessage("Hello~", 0);

    QString filename = QFileDialog::getOpenFileName(this, tr("打开文件"), \
    								".", tr("text  (*.c  *.cpp  *.txt)"));
    if (filename.isEmpty())
    {
        ui->statusBar->showMessage("打开失败", 1500);
        return ;
    }

    QFile file(filename);
    if (!file.open(QIODevice::ReadOnly))
    {
        ui->statusBar->showMessage("打开失败", 1500);
        return ;
    }
    ui->statusBar->showMessage("打开成功", 1500);

    QByteArray buffer = file.readAll();
    ui->textEdit->setText(QString(buffer));
//    ui->textEdit->setText(QString::fromUtf8(buffer));     // 可以
    
//    QString str = QString::fromLocal8Bit(buffer);         // 不行,因为下面是 toUtf8
//    ui->textEdit->setText(QString(str));            

}

void MainWindow::on_action_S_triggered()
{
    QString filename = QFileDialog::getSaveFileName(this, tr("保存文件"), \
    								QDir::homePath(), tr("text  (*.txt)"));
    if (filename.isEmpty())
    {
        ui->statusBar->showMessage("保存失败", 1500);
        return ;
    }

    QFile file(filename);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        ui->statusBar->showMessage("保存失败", 1500);
        return ;
    }

    QTextStream out(&file);
    QString str = ui->textEdit->toPlainText();
    QByteArray buffer;
    buffer.clear();
    buffer = str.toUtf8();

    out << buffer;          // file.write(buffer);
    ui->statusBar->showMessage("保存成功", 1500);
    
    file.close();
}

QIODevice::Text 是一种打开方式,用于文件的读写操作。当以 QIODevice::Text 方式打开文件时,在读取文件内容时,回车换行符(\r\n)会被自动转换为换行符(\n);在写入文件内容时,换行符(\n)会被自动转换为系统的换行符。

在这里插入图片描述

编码转换

QT 界面只支持 utf-8 编码。

QString	fromLocal8Bit(const QByteArray &str);  	// 将QByteArray按照本地编码转换为QString
QString	fromUtf8(const QByteArray &str); 		// 将QByteArray按照utf-8编码转换为QString

QByteArray	toLocal8Bit(); 			// 把QString按照本地编码转换成QByteArray
QByteArray	toUtf8(); 				// 把QString按照utf-8编码转换成QByteArray

事件

概念

事件由 窗口系统 或 QT 自身 以及 外部外设 产生,用以响应各种行为或情况。如:当按下鼠标或释放鼠标时,会产生鼠标事件;按下键盘时出现按键事件。窗体有时需要捕捉这些事件并做出业务逻辑处理。

步骤

文字描述版:

所有的事件处理都是通过重写某个事件方法来实现的

在这里插入图片描述

图片展示版:(以 QEvent::KeyPress 为例)

QEvent::KeyPress ——> QKeyEvent

在这里插入图片描述

QKeyEvent ——> QWidget::keyPressEvent()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

int key() const

在这里插入图片描述

Qt::Key

在这里插入图片描述
在这里插入图片描述

💡 完善登录模块

要求:按回车键触发登录事件,按ESC 键退出登录界面。

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QtWidgets>
#include <QPushButton>
#include <QLabel>
#include <QLineEdit>

class Widget : public QWidget
{
    Q_OBJECT

    QPushButton *btn;
    QLineEdit *username;
    QLineEdit *password;
    QString usr;
    QString pwd;
    QLabel *label;
    QLabel *ulabel;
    QLabel *plabel;

public:
    Widget(QWidget *parent = 0);
    ~Widget();

public slots:
    void verifySlot();

protected:
    void keyPressEvent(QKeyEvent * event);

};

widget.cpp

#include "widget.h"
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    resize(480, 300);

    btn = new QPushButton("Login", this);       // 需要在堆区创建,不能在栈区创建
    btn->move(180, 220);

    ulabel = new QLabel("Username: ", this);
    ulabel->move(60, 80);
    username = new QLineEdit(this);
    username->move(180, 80);
    username->setPlaceholderText("Please input...");

    plabel = new QLabel("Password: ", this);
    plabel->move(60, 160);
    password = new QLineEdit(this);
    password->move(180, 160);
    password->setEchoMode(QLineEdit::Password);
    password->setPlaceholderText("Please input...");

    QObject::connect(btn, SIGNAL(clicked()), this, SLOT(verifySlot()));
    label = new QLabel(this);
}

void Widget::verifySlot()
{
    usr = username->text();
    pwd = password->text();

    label->resize(480, 300);

	if (usr == "0828" && pwd == "0828")
    {
//        label->setText("Logined successfully!");             // 成功显示,但不美观
        qDebug("Logined successfully!");
        this->close();
        
        QWidget *homePage = new QWidget;
        homePage->resize(309, 500);
        homePage->show();
    }
    else
    {
        // QObject::connect(btn, SIGNAL(clicked()), this, SLOT(close()));          
    	// 不能这样写,需要点击两次按钮才会关闭小窗口
        this->close();
    }
}

void Widget::keyPressEvent(QKeyEvent * event)
{
//    qDebug("%x", event->key());
    if(event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
        this->verifySlot();
    else if(event->key() == Qt::Key_Escape)
        this->close();
    else
        QWidget::keyPressEvent(event);
}

Widget::~Widget()
{
    
}

💡 禁止输入特殊字符

在这里插入图片描述

弹框

QToolTip::showText(this->mapToGlobal(this->pos()), "不能使用特殊字符", this);

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include "mytextedit.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    MyTextEdit *mine = new MyTextEdit(this);
}

Widget::~Widget()
{
    delete ui;
}

mytextedit.h

#ifndef MYTEXTEDIT_H
#define MYTEXTEDIT_H

#include <QTextEdit>
#include <QtWidgets>

class MyTextEdit : public QTextEdit				// .cpp, Line 25
{
    Q_OBJECT
public:
    explicit MyTextEdit(QWidget *parent = 0);

signals:

public slots:

protected:
    void keyPressEvent(QKeyEvent * event);

};

#endif // MYTEXTEDIT_H

mytextedit.cpp

#include "mytextedit.h"

MyTextEdit::MyTextEdit(QWidget *parent) :
    QTextEdit(parent)
{
}

void MyTextEdit::keyPressEvent(QKeyEvent * event)
{
    qDebug("%x", event->key());
    switch(event->key())
    {
    case Qt::Key_Backslash:			// 5c、
    case Qt::Key_Slash:				// 2f、
    case Qt::Key_Colon:				// 3a、
    case Qt::Key_Asterisk:			// 2a、
    case Qt::Key_Question:			// 3f、
    case Qt::Key_QuoteDbl:			// 22、
    case Qt::Key_Less:				// 3c、
    case Qt::Key_Greater:			// 3e、
    case Qt::Key_Bar:				// 7c
        QToolTip::showText(this->mapToGlobal(this->pos()), "不能使用特殊字符", this);
        break;
    default:
        QTextEdit::keyPressEvent(event);		// .h, Line 7
        break;
    }
//    if (event->key() == Qt::Key_Backslash)
//        QToolTip::showText(this->mapToGlobal(this->pos()), "不能使用特殊字符", this);
//    else
//        QTextEdit::keyPressEvent(event);
}

运行结果如下:
在这里插入图片描述
在这里插入图片描述

💡 使用鼠标滚轮 操作双向进度条

int numDegrees = event->delta() / 8;		// 滚动的角度,*8就是鼠标滚动的距离
int numSteps = numDegrees / 15;				// 滚动的步数,*15就是鼠标滚动的角度
			// numSteps即上下滚动的步数,体现到数值上是 1/-1。

相关事件类:QWheelEvent

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QtWidgets>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private:
    Ui::Widget *ui;

    QProgressBar *lbar;
    QProgressBar *rbar;
    int lval;
    int rval;

protected:
    void wheelEvent(QWheelEvent * event);
};

#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    this->resize(600, 50);

    // 初始化两个进度条
    lbar = new QProgressBar;
    rbar = new QProgressBar;

    // 为进度条设置默认值
    lbar->setValue(0);
    rbar->setValue(0);
    this->lval= 0;
    this->rval= 0;

    // 取消显示进度条的百分比
    lbar->setTextVisible(false);
    rbar->setTextVisible(false);

    // 使进度条可以纵向拉伸
    lbar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    rbar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

    // 翻转左进度条
    lbar->setInvertedAppearance(true);

    // 添加进度条样式,每个进度条中包含有 1px 的 border边框
    // lbar->setStyleSheet(PROGRESS_LEFT_STYLE);
    // rbar->setStyleSheet(PROGRESS_RIGHT_STYLE);

    // 左右两进度条横向布局
    QHBoxLayout *box = new QHBoxLayout;
    box->addWidget(lbar);
    box->addWidget(rbar);
    box->setMargin(0);
    box->setSpacing(0);

    // 添加进度条两侧的空白,再次横向布局
    QHBoxLayout *hbox = new QHBoxLayout;
    hbox->addStretch(1);
    hbox->addLayout(box, 28);
    hbox->addStretch(1);
    hbox->setMargin(0);
    hbox->setSpacing(0);

    // 添加进度条上下的空白,然后纵向布局
    QVBoxLayout *vbox = new QVBoxLayout(this);
    vbox->addStretch(1);
    vbox->addLayout(hbox, 5);
    vbox->addStretch(1);
    vbox->setMargin(0);
    vbox->setSpacing(0);
}

void Widget::wheelEvent(QWheelEvent * event)
{
    int numDegrees = event->delta() / 8;
    int numSteps = numDegrees / 15;

//    qDebug() << numDegrees << numSteps;       // ±15, ±1

    if (numDegrees < 0)
    {
        if (this->rval < 0)
        {
            this->rval = 0;

            this->lval += 10;
            if (this->lval >= 100)
                this->lval = 100;

            lbar->setValue(this->lval);
            qDebug() << "left: " << this->lval;
        }

        this->rval -= 10;
        rbar->setValue(this->rval);
        qDebug() << "right: " << this->rval;
    }
    else if (numDegrees > 0)
    {
        if (this->lval < 0)
        {
            this->lval = 0;

            this->rval += 10;
            if (this->rval >= 100)
                this->rval = 100;

            rbar->setValue(this->rval);
            qDebug() << "right: " << this->rval;
        }

        this->lval -= 10;
        lbar->setValue(this->lval);
        qDebug() << "left: " << this->lval;
    }
    else { }
}

Widget::~Widget()
{
    delete ui;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值