1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include <QKeySequence> #include <QMenuBar> #include <QDebug> mainWindow_1::mainWindow_1 (QMainWindow* parent) : QMainWindow (parent) { QMenuBar* menu = new QMenuBar (this ); this ->setMenuBar (menu); QMenu* file = new QMenu ("文件" , this ); QMenu* edit = new QMenu ("编辑" , this ); menu->addMenu (file); menu->addMenu (edit); QAction* open_file = new QAction ("open file" , this ); QAction* new_file = new QAction ("new file" , this ); file->addAction (open_file); file->addSeparator (); file->addAction (new_file); new_file->setShortcut (QKeySequence (Qt::CTRL + Qt::Key_N)); open_file->setShortcut (QKeySequence (Qt::CTRL + Qt::Key_O)); connect (new_file, &QAction::triggered, [=]() { qDebug () << "新建文件成功" << Qt::endl; }); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 QToolBar* toolBar = new QToolBar (this ); this ->addToolBar (toolBar); QAction* tool_copy = new QAction ("copy" , this ); toolBar->addAction (tool_copy); toolBar->addSeparator (); toolBar->addAction (new_file); toolBar->addAction (open_file); toolBar->setFloatable (false ); toolBar->setAllowedAreas (Qt::LeftToolBarArea | Qt::RightToolBarArea);
状态栏 1 2 3 4 5 6 QLabel* lable_left = new QLabel ("左侧提示信息" , this ); QLabel* lable_right = new QLabel ("右侧提示信息" , this ); statusBar->addWidget (lable_left); statusBar->addPermanentWidget (lable_right);
铆接部件 1 2 3 4 5 6 7 8 9 10 11 QDockWidget* dockwidget = new QDockWidget ("dockwidget" , this ); this ->addDockWidget (Qt::TopDockWidgetArea, dockwidget); dockwidget->setAllowedAreas (Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea); QTextEdit* text_edit = new QTextEdit (this ); text_edit->setText ("这是一个文本域" ); this ->setCentralWidget (text_edit);
1 2 3 4 5 6 7 8 9 10 11 QListWidgetItem* item = new QListWidgetItem ("this is a listWidgetitem" ); ui->listWidget_1->addItem (item); QStringList list; list << "this is test 1" << "this is test 2" << "this is test 3" ; ui->listWidget_1->addItems (list); connect (ui->listWidget_1, &QListWidget::itemClicked, [](QListWidgetItem* item){ qDebug () << item->text (); })
运行结果
通过UI界面设计
不能在运行时添加项目值
通过代码设计
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include "mainwindow.h" #include "ui_mainwindow.h" #include <QStringList> #include <QTreeWidgetItem> #include <QList> #include <QDebug> MainWindow::MainWindow (QWidget *parent) : QMainWindow (parent) , ui (new Ui::MainWindow) { ui->setupUi (this ); QStringList list; list << "Country" << "Language" ; ui->treeWidget->setHeaderLabels (list); QTreeWidgetItem* item_China = new QTreeWidgetItem (QStringList () << "China" << "汉语" ); QTreeWidgetItem* item_Japan = new QTreeWidgetItem (QStringList () << "Japan" << "Japanese" ); QTreeWidgetItem* item_Han = new QTreeWidgetItem (item_China, QStringList () << "汉族" << "汉语" ); ui->treeWidget->addTopLevelItems (QList <QTreeWidgetItem*>({item_China, item_Japan})); connect (ui->treeWidget, &QTreeWidget::itemClicked, [](QTreeWidgetItem* item, int column){ qDebug () << item->text (column); }); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 #include "mainwindow.h" #include "ui_mainwindow.h" #include <QTableWidget> #include <QTableWidgetItem> #include <QStringList> #include <QDebug> MainWindow::MainWindow (QWidget *parent) : QMainWindow (parent) , ui (new Ui::MainWindow) { ui->setupUi (this ); int c = 3 ; int r = 5 ; ui->tableWidget->setColumnCount (c); ui->tableWidget->setRowCount (r); QStringList listHeaderItem ({"Name" , "Gender" , "Age" }) ; ui->tableWidget->setHorizontalHeaderLabels (listHeaderItem); QStringList listNames ({"Neo" , "Bill" , "Rose" , "Joke" , "Tom" }) ; QStringList listGender ({"Male" , "Male" , "Female" , "Male" , "Male" }) ; for (int i = 0 ; i < r; ++i) { ui->tableWidget->setItem (i, 0 , new QTableWidgetItem (listNames[i])); ui->tableWidget->setItem (i, 1 , new QTableWidgetItem (listGender[i])); ui->tableWidget->setItem (i, 2 , new QTableWidgetItem (QString::number (i + 30 ))); } connect (ui->tableWidget, &QTableWidget::itemClicked, [](QTableWidgetItem* item){ qDebug () << item->text (); }); connect (ui->tableWidget, &QTableWidget::cellClicked, [](int row, int column){ qDebug () << "row = " << row << " column = " << column; }); }
QLable控件 获取QLable文本
设置图片setPixmap 1 2 QPixmap pix ("://src_img/icon_1.png" ) ; ui->label_2->setPixmap (pix);
设置动画并播放 1 2 3 4 5 6 7 QMovie* movie_gif = new QMovie ("://src_img/coffee-3567_512.gif" ); ui->label_2->setMovie (movie_gif); connect (ui->pushButtonPlay, &QPushButton::clicked, movie_gif, &QMovie::start); connect (ui->pushButtonPause, &QPushButton::clicked, movie_gif, &QMovie::stop);
自定义控件
定义一个自定义控件
自行添加控件
在其他界面添加容器存放自定义控件
提升控件到自定义控件
运行结果
让界面动起来,spinBox数值改变,让horizontalSlider进度条同步运动,反之,spinBox数值也要同步改变
1 2 3 4 5 6 7 8 9 10 11 12 13 void (QSpinBox:: *p)(int ) = &QSpinBox::valueChanged; connect (ui->spinBox, p, [=](int ti){ ui->horizontalSlider->setValue (ti); }); connect (ui->horizontalSlider, &QSlider::sliderMoved, [=](int val){ ui->spinBox->setValue (val); }); connect (ui->horizontalSlider, &QSlider::valueChanged, [=](int val){ ui->spinBox->setValue (val); });
自定义控件提供外部接口
在自定义控件头文件定义公共函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class myWidget : public QWidget{ Q_OBJECT public : explicit myWidget (QWidget *parent = nullptr ) ; ~myWidget (); void func_setSliderVal (int val) ; int func_SliderVal (void ) ; private : Ui::myWidget *ui; };
在自定义控件函数实现cpp文件实现函数
1 2 3 4 5 6 7 8 9 void myWidget::func_setSliderVal (int val) { ui->horizontalSlider->setValue (val); } int myWidget::func_SliderVal (void ) { return ui->horizontalSlider->value (); }
调用公共函数接口
1 2 3 4 5 6 connect (ui->pushButtonSetHalf, &QPushButton::clicked, [=](){ ui->widget->func_setSliderVal (50 ); }); connect (ui->pushButtonPrintSliderVal, &QPushButton::clicked, [=](){ qDebug () << ui->widget->func_SliderVal (); });
对话框 QtDialog 模态对话框 (独占)Qdialog 1 2 3 4 5 6 #include <QDialog> QDialog* dlg = new QDialog (this ); dlg->resize (300 , 300 ); dlg->exec (); qDebug () << "显示模态对话框" << Qt::endl;
非模态对话框 (非独占)QDialog 1 2 3 4 5 6 #include <QDialog> QDialog* dlg = new QDialog (this ); dlg->resize (300 , 300 ); dlg->show (); qDebug () << "显示模态对话框" << Qt::endl;
消息对话框 QMessageBox 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <QMessageBox> QMessageBox::StandardButton ret; ret = QMessageBox::question (this , "question" , "this is a question" , QMessageBox::Save | QMessageBox::Cancel, QMessageBox::Cancel); if (ret == QMessageBox::Save) { qDebug () << "files saved!" ; } else if (ret == QMessageBox::Cancel) { qDebug () << "cancel save file" ; }
字体对话框 QFontDialog 1 2 3 4 5 6 7 8 9 #include <QFont> #include <QFontDialog> bool yes; QFont font; font = QFontDialog::getFont (&yes, QFont ("宋体" ), this ); if (yes == true ){ qDebug () << "the font is :" << font.families () << " , font size is :" << font.pointSize () << Qt::endl; }
颜色对话框 QColorDialog 1 2 3 4 5 6 #include <QColorDialog> #include <QColor> QColor color; color = QColorDialog::getColor (); qDebug () << "red color is " << color.red () << Qt::endl;
文件对话框 QFileDialog 1 2 3 4 5 6 7 #include <QFileDialog> QString fileName; fileName = QFileDialog::getOpenFileName (this , "files" , "F:/Pictures" , "*.png" ); qDebug () << "The file is " << fileName << Qt::endl;
布局管理器 Qt 提供的布局中以下三种是我们最常用的 :
; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 2. ```QVBoxLayout```:按照竖直方向从上到下布局 3. ```QGridLayout```:在一个网格中进行布局 ,类似HTML 的 table <img src="https://huiblog.oss-cn-hangzhou.aliyuncs.com/img/note/Qt/Qt_note_layout.png" style="zoom: 67%;" /> **让界面动起来** ```c++ #include "mainwindow.h" #include "ui_mainwindow.h" #include <QPushButton> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); // 单击登录获取用户名 connect(ui->pushButtonLogIn, &QPushButton::clicked, [=](){ qDebug() << "User name is " << ui->lineEditUserName->text(); qDebug() << "Password is " << ui->lineEditPassWord->text(); }); connect(ui->pushButtonExit, &QPushButton::clicked, [=](){ this->close(); }); } MainWindow::~MainWindow() { delete ui; }
容器Container
组容器 Group Box
1 2 3 4 5 ui->radioButtonMale->setChecked (true ); connect (ui->radioButtonMale, &QPushButton::clicked, [=](){ qDebug () << "your gender choice is " << ui->radioButtonMale->text () << Qt::endl; });
下拉列表框 ComboBox
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include "widget.h" #include "ui_widget.h" #include <QStringList> #include <QComboBox> #include <QDebug> Widget::Widget (QWidget *parent) : QWidget (parent) , ui (new Ui::Widget) { ui->setupUi (this ); QStringList list_options (QList<QString>({"New file" , "New folder" , "Save file" })) ; ui->comboBox->addItems (list_options); ui->comboBox->setCurrentIndex (2 ); void (QComboBox::* p)(int ) = &QComboBox::currentIndexChanged; connect (ui->comboBox, p, [=](int index){ qDebug () << "Index = " << index << " text = " << ui->comboBox->currentText (); }); } Widget::~Widget () { delete ui; }
Qt消息机制和事件 Qt事件的概述和定义 Qt 中的事件是通过事件处理系统定义的。事件处理系统是 Qt 中一种基于对象的系统,提供了一种方法来处理 GUI 中的用户输入和窗口系统事件。
在 Qt 中,事件是由 QEvent 类定义的,QEvent 类是所有事件类的基类。每个事件类都有自己的类型和数据,如 QMouseEvent 类,它记录了鼠标事件的信息,如鼠标位置和按键状态。
在 Qt 中,通常是通过继承 QObject 类并重写事件处理方法来定义事件处理。例如,要处理鼠标按下事件,可以重写 QWidget 的 mousePressEvent() 方法。在事件发生时,Qt 会自动调用该方法并将事件传递给它。
事件处理方法的名称通常是以 “event” 为后缀的,如 mousePressEvent(),它们通常是用于处理特定类型的事件的虚函数。
例子:用QLabel展示鼠标相关事件 首先,我们从 QLable继承了一个类,并重写了 enterEvent() 和 leaveEvent() 方法。当鼠标进入窗口时,enterEvent() 方法将会被调用,打印 “Mouse entered the label” 字符串;当鼠标离开窗口时,leaveEvent() 方法将会被调用,打印 “Mouse left the label” 字符串。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #ifndef MYLABEL_H #define MYLABEL_H #include <QLabel> class MyLabel : public QLabel{ Q_OBJECT protected : void enterEvent (QEnterEvent *event) ; void leaveEvent (QEvent *event) ; void mouseMoveEvent (QMouseEvent* event) ; void mousePressEvent (QMouseEvent* event) ; public : explicit MyLabel (QWidget *parent = nullptr ) ; signals: }; #endif
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #include "mylabel.h" #include <QPoint> #include <QCursor> #include <QMouseEvent> MyLabel::MyLabel (QWidget *parent) : QLabel{parent} { } void MyLabel::enterEvent (QEnterEvent *event) { Q_UNUSED (*event); qDebug () << "Mouse entered the label" ; } void MyLabel::leaveEvent (QEvent *event) { Q_UNUSED (*event); qDebug () << "Mouse left the label" ; } void MyLabel::mouseMoveEvent (QMouseEvent* event) { Q_UNUSED (event); qDebug () << "The mouse is pressed and moved in the Label, the position is x = " << event->x () << " y = " << event->y (); } void MyLabel::mousePressEvent (QMouseEvent* event) { Q_UNUSED (event); QPoint p = QCursor::pos (); if (event->button () == Qt::LeftButton) { qDebug () << "The left mouse button is pressed and position is " << p; }else if (event->button () == Qt::RightButton){ qDebug () << "The right mouse button is pressed and position is " << p; } }
“protected” 是 C++ 中的一个修饰符,用于限制类成员的访问权限。
当一个类的成员被声明为 “protected” 时,它只能在这个类的内部和它的派生类(子类)中被访问。这意味着,在这个类的外部,它不能被直接访问。但是,如果你继承这个类,并且创建了一个子类,那么在子类中,你可以通过对象访问这个 protected 成员。
使用 protected 修饰符可以使继承关系更加紧密,并且防止其他代码意外地修改类的内部数据。
Q_UNUSED 宏用于告诉编译器一个变量是未使用的,以避免编译器发出未使用变量的警告。
事件函数一般都是虚函数,所以都需要重写
事件分发器 Qt 中的事件分发器是用于处理应用程序中的事件的机制。它从窗口系统接收事件(例如键盘输入、鼠标点击等),并将它们分配给相应的 GUI 对象。
Qt 使用事件循环和事件分发器(QCoreApplication)来管理事件。每个 Qt 应用程序都有一个主事件循环,它可以接收和分派事件。您可以在主函数中使用 QCoreApplication::exec() 函数来启动事件循环。
事件分发器会传递事件给与之相关的 GUI 对象。每个 GUI 对象都可以重写 QObject 类的 event() 函数,以处理特定类型的事件。
重写事件分发器 例如,你可以在 QWidget 子类中重写 event() 函数,以处理鼠标点击事件:
1 2 3 4 5 6 7 8 bool MyWidget::event (QEvent *event) { if (event->type () == QEvent::MouseButtonPress) { return true ; } return QWidget::event (event); }
如果您处理了事件并返回了 true,则表示该事件已被处理,不再需要传递给其他对象。如果您未处理事件并返回 false,则该事件将继续传递给其他对象。
其他事件处理器 此外,Qt 还提供了一些其他方法来处理事件,例如:
信号与槽:您可以在一个对象上定义信号,并在另一个对象上连接该信号以处理特定事件。
事件过滤器:您可以在程序中安装事件过滤器,以在事件分发之前对事件进行处理。
事件处理器:您可以定义事件处理器来处理特定类型的事件。
Qt 事件分发器是一个灵活的机制,你可以根据你的应用程序需求使用不同的方法处理事件。
事件过滤器 Qt 事件过滤器是一种处理事件的方法,可以在事件分发之前对事件进行处理。您可以在程序中安装事件过滤器,以捕获应用程序中的事件。事件过滤器是一个 QObject 的子类,可以实现 eventFilter 函数来处理事件。
使用事件过滤器的示例 示例一 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class EventFilter : public QObject{ public : bool eventFilter (QObject *watched, QEvent *event) { if (event->type () == QEvent::KeyPress) { return true ; } return false ; } }; int main (int argc, char *argv[]) { QApplication a (argc, argv) ; EventFilter filter; a.installEventFilter (&filter); return a.exec (); }
在上面的代码中,我们定义了一个名为 EventFilter 的类,该类继承自 QObject 并实现了 eventFilter 函数。我们在主函数中安装了该事件过滤器,并通过 QCoreApplication::installEventFilter 函数实现。现在,当有任何事件发生时,该事件将先到达事件过滤器,该过滤器可以处理事件,并返回 true 或 false 来指示是否处理了该事件。如果事件被处理,则不会传递给其他对象;如果未被处理,则该事件将继续分发。
示例二 在下面代码中,我们首先在自己类中的构造函数部分安装或者加载事件过滤器 。
1 2 3 4 5 6 MyLabel::MyLabel (QWidget *parent) : QLabel{parent} { this ->installEventFilter (this ); }
在类头文件声明事件过滤器函数
1 2 3 4 bool eventFilter (QObject *watched, QEvent *event) override ;
具体函数实现
1 2 3 4 5 6 7 8 9 10 11 12 13 bool MyLabel::eventFilter (QObject *watched, QEvent *event) { if (watched == this ) { if (event->type () == QEvent::MouseButtonPress) { qDebug () << "A mouse press event occurs" ; return true ; } } return QLabel::eventFilter (watched, event); }
注意事项 事件过滤器和被安装过滤器的组件必须在同一线程 ,否则 ,过滤器将不起作用。另外 ,如果在安装过滤器之后 ,这两个组件到了不同的线程 , 那么 ,只有等二者重新回到同一线程的时候过滤器才会有效 。
这种全局的事件过滤器将会 在所有其它特性对象的事件过滤器之前调用 。 尽管很强大 , 但这种行为会严重降低整个应用程序的事件分发效率 。
定时器控件 QTimer Qt提供了一个定时器类QTimer,它可以在指定的时间间隔内触发信号,从而实现定时任务。可以使用QTimer::start()方法启动定时器,并通过setInterval()方法设置时间间隔。定时器可以在单次触发或多次触发信号,可以通过setSingleShot()方法控制。
案例一 函数中使用 1 2 3 4 5 6 7 8 9 10 11 12 13 #include <QTimer> #include <QDebug> int main (int argc, char *argv[]) { QTimer timer; timer.setInterval (1000 ); QObject::connect (&timer, &QTimer::timeout, [](){ qDebug () << "timeout" ; }); timer.start (); return 0 ; }
以上代码将每隔1秒输出一次”timeout”。
案例二 启动一个定时器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #ifndef WIDGET_H #define WIDGET_H #include <QWidget> QT_BEGIN_NAMESPACE namespace Ui { class Widget ; }QT_END_NAMESPACE class Widget : public QWidget{ Q_OBJECT public : Widget (QWidget *parent = nullptr ); ~Widget (); protected : virtual void timerEvent (QTimerEvent *event) override ; private : Ui::Widget *ui; }; #endif
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include "widget.h" #include "ui_widget.h" Widget::Widget (QWidget *parent) : QWidget (parent) , ui (new Ui::Widget) { ui->setupUi (this ); this ->startTimer (1000 ); } Widget::~Widget () { delete ui; } void Widget::timerEvent (QTimerEvent *event) { static int timeCount; ui->label_timer->setText (QString::number (timeCount++)); }
案例二 启动多个定时器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #ifndef WIDGET_H #define WIDGET_H #include <QWidget> QT_BEGIN_NAMESPACE namespace Ui { class Widget ; }QT_END_NAMESPACE class Widget : public QWidget{ Q_OBJECT public : Widget (QWidget *parent = nullptr ); ~Widget (); protected : virtual void timerEvent (QTimerEvent *event) override ; private : Ui::Widget *ui; int timerId_1; int timerId_2; }; #endif
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include "widget.h" #include "ui_widget.h" Widget::Widget (QWidget *parent) : QWidget (parent) , ui (new Ui::Widget) { ui->setupUi (this ); this ->timerId_1 = this ->startTimer (1000 ); this ->timerId_2 = this ->startTimer (2000 ); } Widget::~Widget () { delete ui; } void Widget::timerEvent (QTimerEvent *event) { static int timeCount_1; static int timeCount_2; if (event->timerId () == this ->timerId_1) { ui->label_timer_1->setText ("Timer_1 : " + QString::number (timeCount_1++)); } if (event->timerId () == this ->timerId_2) { ui->label_timer_2->setText ("Timer_2 : " + QString::number (timeCount_2++)); } }
案例三 通过定时器对象启动 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #ifndef WIDGET_H #define WIDGET_H #include <QWidget> QT_BEGIN_NAMESPACE namespace Ui { class Widget ; }QT_END_NAMESPACE class Widget : public QWidget{ Q_OBJECT public : Widget (QWidget *parent = nullptr ); ~Widget (); protected : virtual void timerEvent (QTimerEvent *event) override ; private : Ui::Widget *ui; }; #endif
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include "widget.h" #include "ui_widget.h" #include <QTimer> #include <QPushButton> Widget::Widget (QWidget *parent) : QWidget (parent) , ui (new Ui::Widget) { ui->setupUi (this ); QTimer* timer_test = new QTimer (this ); static int timeCount_3; connect (timer_test, &QTimer::timeout, [=](){ ui->label_timer_3->setText (QString::number (timeCount_3++)); }); connect (ui->pushButton_timerStart, &QPushButton::clicked, [=](){ timer_test->start (3000 ); }); connect (ui->pushButton_timerStop, &QPushButton::clicked, [=](){ timer_test->stop (); }); } Widget::~Widget () { delete ui; }
Qt绘图:QPainter、QPainterDevice、QPainterEngine Qt绘图系统基于QPainter 、QPainterDevice 和QPaintEngine 的三个类**QPainter(画家)使用 QPaintEngine(绘图引擎)在 QPainterDevice(绘图设备)**上在进行绘画。
案例一 绘制窗口背景图 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #ifndef WIDGET_H #define WIDGET_H #include <QWidget> QT_BEGIN_NAMESPACE namespace Ui { class Widget ; }QT_END_NAMESPACE class Widget : public QWidget{ Q_OBJECT public : Widget (QWidget *parent = nullptr ); ~Widget (); protected : virtual void paintEvent (QPaintEvent* event) ; private : Ui::Widget *ui; }; #endif
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include "widget.h" #include "ui_widget.h" #include <QPainter> #include <QPixmap> Widget::Widget (QWidget *parent) : QWidget (parent) , ui (new Ui::Widget) { ui->setupUi (this ); this ->resize (768 , 512 ); } Widget::~Widget () { delete ui; } void Widget::paintEvent (QPaintEvent *event) { QPainter* painter = new QPainter (this ); QPixmap pix_png ("://img/test_img.png" ) ; pix_png.scaled (this ->width (), this ->height ()); painter->drawPixmap (0 , 0 , this ->width (), this ->height (), pix_png); }
案例二 通过update()函数重载绘图事件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #ifndef WIDGET_H #define WIDGET_H #include <QWidget> QT_BEGIN_NAMESPACE namespace Ui { class Widget ; }QT_END_NAMESPACE class Widget : public QWidget{ Q_OBJECT public : Widget (QWidget *parent = nullptr ); ~Widget (); protected : virtual void paintEvent (QPaintEvent* event) ; virtual void resizeEvent (QResizeEvent* event) ; private : void updateButtonPosition () ; Ui::Widget *ui; }; #endif
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 #include "widget.h" #include "ui_widget.h" #include <QPainter> #include <QPixmap> #include <QPushButton> #include <QDebug> Widget::Widget (QWidget *parent) : QWidget (parent) , ui (new Ui::Widget) { ui->setupUi (this ); this ->resize (768 , 512 ); connect (ui->pushButton_picMove, &QPushButton::clicked, [&](){ this ->update (); }); } Widget::~Widget () { delete ui; } void Widget::paintEvent (QPaintEvent *event) { QPainter* painter = new QPainter (this ); QPixmap pix_png ("://img/test_img.png" ) ; pix_png.scaled (this ->width (), this ->height ()); static int x = 0 ; painter->drawPixmap (x, 0 , pix_png.width (), pix_png.height (), pix_png); x += 20 ; if (x >= this ->width ()) { x = 0 ; } } void Widget::resizeEvent (QResizeEvent *event) { updateButtonPosition (); QWidget::resizeEvent (event); } void Widget::updateButtonPosition () { int x = (this ->width () - ui->pushButton_picMove->width ()) * 0.5 ; int y = this ->height () - ui->pushButton_picMove->height (); ui->pushButton_picMove->move (x, y); }
画家QInpainter的其他绘图函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #ifndef WIDGET_H #define WIDGET_H #include <QWidget> QT_BEGIN_NAMESPACE namespace Ui { class Widget ; }QT_END_NAMESPACE class Widget : public QWidget{ Q_OBJECT public : Widget (QWidget *parent = nullptr ); ~Widget (); protected : virtual void paintEvent (QPaintEvent* event) ; private : Ui::Widget *ui; }; #endif
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include "widget.h" #include "ui_widget.h" #include <QPainter> #include <QDebug> Widget::Widget (QWidget *parent) : QWidget (parent) , ui (new Ui::Widget) { ui->setupUi (this ); this ->resize (800 , 600 ); } Widget::~Widget () { delete ui; } void Widget::paintEvent (QPaintEvent *event) { Q_UNUSED (event); qDebug () << "this is a test" ; QPainter* painter = new QPainter (this ); painter->drawLine (0 , 0 , 300 , 300 ); painter->setPen (Qt::red); painter->drawRect (30 , 30 , 50 , 80 ); painter->drawEllipse (400 , 300 , 200 , 200 ); painter->drawEllipse (200 , 200 , 300 , 200 ); }
绘图设备 QPaintDivice 概述 Qt6 的绘图设备是 QPaintDevice 类。QPaintDevice 是所有 Qt 绘图类的基类,包括 QPixmap、QImage、QPicture、QWidget、QPrinter 等。它定义了一个公共的接口,所有的绘图类都必须实现它。
QPaintDevice 包含了一些关于绘图的基本信息,例如:分辨率、每英寸的像素数等。它也提供了一个关于绘图的状态的接口,例如:画家,画笔,画刷等。
在绘图时,通过在画家上设置合适的画笔、画刷等,并调用画家的绘图函数,就可以在 QPaintDevice 上绘图了。
QBitmap QBitmap 是 Qt GUI 框架中的 QPixmap 的子类。它用于表示单色(1位深度)位图。与基于 QImage 类并支持全彩图像的 QPixmap 不同,QBitmap 仅支持二进制图像。使用 QBitmap 而不是 QImage 的优点在于,QBitmap 针对更快的渲染进行了优化,与 QImage 相比,内存使用更少。它通常用于图像需要作为掩码使用的情况,例如创建自定义光标或突出显示部件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Widget::Widget (QWidget *parent) : QWidget (parent) , ui (new Ui::Widget) { ui->setupUi (this ); this ->resize (800 , 600 ); QBitmap bitMap (300 , 300 ) ; QPainter bitMapPainter (&bitMap) ; bitMapPainter.drawEllipse (QPoint (150 , 150 ), 100 , 100 ); bitMap.save ("C:\\0_WorkSpace\\QT_Learning\\test_QInpainter\\test.png" ); }
QImage QImage 是 Qt GUI 框架中的图像操作类。它用于表示和操作数字图像。与 QPixmap 不同,后者针对屏幕显示进行了优化,QImage 针对图像处理进行了优化,并提供了许多图像操作函数,如缩放、裁剪、颜色校正等。QImage 支持广泛的图像格式,包括 BMP、GIF、JPEG、PNG 等,可以用于在屏幕上显示图像或将图像保存到磁盘。QImage 中的图像数据以与用于显示图像的格式无关的格式存储,使得更容易在内存中处理和操作图像。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 Widget::Widget (QWidget *parent) : QWidget (parent) , ui (new Ui::Widget) { ui->setupUi (this ); this ->resize (800 , 600 ); QImage image; image.load ("://src_img/icon_1.png" ); QPainter imagePainter (&image) ; for (int i = 100 ; i < 150 ; ++i) { for (int j = 100 ; j < 150 ; ++j) { int value = qRgb (0 , 255 , 0 ); image.setPixel (i, j, value); } } image.save ("C:\\0_WorkSpace\\QT_Learning\\test_QInpainter\\test.png" ); }
QPicture QPicture 是 Qt GUI 框架中的矢量图形类。它用于存储并重现 QPainter 绘制的图形。QPicture 和 QPixmap、QImage 不同,它不用于直接显示图形,而是用于存储绘制命令以及绘制时所需的数据,适用于需要高效存储和重现图形的应用场景,例如图形序列化。QPicture 可以使用 QPainter 记录,也可以加载和保存为二进制文件。当 QPicture 被重现时,QPainter 可以将其绘制到其他绘图设备,例如 QPixmap、QImage、QPrinter、QOpenGLPaintDevice 等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #ifndef WIDGET_H #define WIDGET_H #include <QWidget> QT_BEGIN_NAMESPACE namespace Ui { class Widget ; }QT_END_NAMESPACE class Widget : public QWidget{ Q_OBJECT public : Widget (QWidget *parent = nullptr ); ~Widget (); protected : virtual void paintEvent (QPaintEvent* event) ; private : Ui::Widget *ui; }; #endif
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 #include "widget.h" #include "ui_widget.h" #include <QPainter> #include <QPicture> Widget::Widget (QWidget *parent) : QWidget (parent) , ui (new Ui::Widget) { ui->setupUi (this ); this ->resize (800 , 600 ); QPicture picture; QPainter picturePainter; picturePainter.begin (&picture); picturePainter.drawEllipse (50 , 50 , 100 , 100 ); picturePainter.end (); picture.save ("C:\\0_WorkSpace\\QT_Learning\\test_QInpainter\\steps.st" ); } Widget::~Widget () { delete ui; } void Widget::paintEvent (QPaintEvent *event) { Q_UNUSED (event); QPicture picture; QPainter picturePainter (this ) ; picture.load ("C:\\0_WorkSpace\\QT_Learning\\test_QInpainter\\steps.st" ); picturePainter.drawPicture (100 , 100 , picture); }