🌼🌼学习日志(新手疑难问题解决思路)🌼🌼
🔺如何制作一个非模态窗口
模态和非模态简单的说就是一个新的窗口打开之后还能不能操作旧的窗口,模态是不能操控,而非模态是可以操控
在Qt中调用setWindowModality()
函数
在这个函数里面包含了三个可以调整模态方式的参数
Qt::NonModal ❀The window is not modal and does not block input to other windows.
非模态对话框
Qt::WindowModal ❀The window is modal to a single window hierarchy and blocks input to its parent window, all grandparent windows, and all siblings of its parent and grandparent windows.
窗口级模态对话框,即只会阻塞父窗口、父窗口的父窗口及兄弟窗口。(半模态对话框)
Qt::ApplicationModal ❀The window is modal to the application and blocks input to all windows.
应用程序级模态对话框,即会阻塞整个应用程序的所有窗口。(半模态对话框)
这个是一个非模态窗口,创建之后在旧窗口和新窗口都可以进行操作
=========================================
🔺事件过滤器(在label上面使用painter)
在Qt中,当一个事件发生时(例如鼠标点击或某个键盘上的按键按下),其传递顺序如图所示。从这个图可以看出,事件过滤器首先获得事件,其次才是部件的 event 函数,最后是部件的事件处理函数。(baidu)
而我们需要使用事件过滤器可以简单的认为 我们想让一个Label拥有被Painter作画的能力,或者点击Label之后可以执行一些命令,就像按钮那样。
就需要事件过滤,实际上事件过滤器也就是干这种事情的
首先,头文件里面声明
bool TheMainWindowadmin::eventFilter(QObject *watched, QEvent *event);
//固定的声明格式
然后,要给需要过滤事件的组件安装事件过滤器
ui->information_down->installEventFilter(this);//安装事件过滤器
//information_down是我的一个Label的名字
下一步在cpp文件中实现:
//事件过滤函数 --- 用于Paint事件在label上的实现
bool TheMainWindowadmin::eventFilter(QObject *watched, QEvent *event) //用过滤器eventFilter()
//拦截QLabel中的QEvent::Paint事件
{
if(watched ==ui->information_down && event->type() == QEvent::Paint)
PainterEvent();
return QWidget::eventFilter(watched,event);
}
★★★该函数在 QObject 类中声明为一个虚函数,因此只能由 QObject 的子类继承使用★★★
注意:以下的前四条内容是这个函数的框架内容
🔺bool是类型,也就是说这个东西返回了一个布尔类型
🔺TheMainWindowadmin是头文件的名字,也是我这个函数声明的地方,是个作用域,每个人的代码里面都不同
🔺eventFilter 中文翻译过来就是事件过滤器,其实是这个函数的名字
🔺(QObject *watched, QEvent *event) 是参数,是固定的
👇👇👇详细请看👇👇👇
实际上我们不是自己定义的eventFilter,而是这个函数本身就是QObject里面的虚函数,我们是重写,重写虚函数的方法👉照抄一遍。
而且这个虚函数是保护成员,所以只能在QObject本身和子类里面来用
🌼🌼🌼🌼🌼🌼🌼🌼🌼🌼🌼🌼🌼🌼🌼🌼🌼🌼🌼🌼🌼🌼🌼🌼
🔺 if(watched == ui->information_down && event->type() == QEvent::Paint)
ui->information_down 在我的项目里面是个Label
watched == 的后面写你要作用的对象。
event->type() == 的后面写你要过滤的事件。
🔺PainterEvent() 是我项目里面定义的函数,在里面定义画笔,然后让画笔画画,要写在上述代码的固定位置
🔺返回值如上述代码,是固定的这样写的
=========================================================
🔺利用事件过滤器做一个可以点击的Label
学会一种就可以举一反三
Label默认下被点击是不会有反应的,但是我们可以通过事件过滤器赋予Label一个被点击的反应
🌼*[案例:点击Label可以选择图片,并在Label上展现选取的图片]*🌼
我们会用到鼠标的点击事件,所以要包含头文件#include <QMouseEvent>
我们需要用到connect,需要信号和槽,信号是鼠标点击事件发出来的。我们只需要一个自定义的槽,槽内实现打开文件夹,选取图片,展示图片三个功能即可
#include <QMouseEvent>
class Commodity_management : public QWidget
{
Q_OBJECT
public:
bool eventFilter(QObject *watched, QEvent *event);//事件过滤器
public slots:
void openImg();//打开图片的槽函数
};
🔺因为打开图片需要用到QFileDialog::getOpenFileName函数和QImage,需要
#include <QFileDialog>
#include <QImage>
🔺openImg()函数内容:
//打开图片
void Commodity_management::openImg()
{ //获取图片,以及图片文件
QString OpenFile;
QImage image;
//打开文件夹中的图片
OpenFile = QFileDialog::getOpenFileName(this,"Please choose an image about commodity",
"",
"Image Files(*.jpg *.png *.bmp *.pgm *.pbm);;All(*.*)");
//显示图片
if(OpenFile != ""){
if( image.load(OpenFile)){
ui->picture_add->setPixmap(QPixmap::fromImage(image));
}
}
}
getOpenFileName函数的使用详细请见:
原文链接:https://blog.csdn.net/weixin_42704090/article/details/90400427
🔺事件过滤器eventFilter函数内容
bool Commodity_management::eventFilter(QObject *watched, QEvent *event)
{
if(watched ==ui->picture_add && event->type() == QEvent::MouseButtonPress){//鼠标点击
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event); //事件转换
if(mouseEvent->button() == Qt::LeftButton){
Commodity_management::openImg();//选取图片
return true;
}else{
return false;
}
}else{
return QWidget::eventFilter(watched,event);
}
}
事件转换是必须的,需要把QEvent事件转换成QMouseEvent事件,使用鼠标事件。如果想要键盘事件,可以把QMouseEvent改成QkeyEvent,其他同理
🔺picture_add 是我Label的名字
🔺QEvent::MouseButtonPress 是鼠标点击事件
🔺mouseEvent->button() == Qt::LeftButton
是鼠标事件里面的点击与Qt::LeftButton(Qt里面的左键事件)相匹配
[效果]
点击之后:
=========================================================
🔺关于窗口close并不是关闭窗口,而是隐藏窗口
调用close()并不会销毁对象,设置属性setAttribute(Qt::WA_DeleteOnClose)才会在close后销毁对象。如果没有设置属性,则效果跟hide()、setVisible()差不多,都只是起一个隐藏作用。
详细:https://blog.csdn.net/wzz953200463/article/details/101101135
=========================================================
🔺关闭一个窗口后,另一个窗口的数据自动更新
应用于A窗口表格显示所有用户,A窗口中有一个添加用户的按钮来打开一个添加窗口B,B窗口添加成功并且关闭后A窗口自动更新了新的用户表格
原理:
假如我们的页面(User_management_Widget
)是这样的
右边的增加用户按钮的信号与槽是
connect(ui->Add_Users,&QPushButton::clicked,this,&User_management_Widget::AddUsers);//增加用户
其中,AddUsers槽函数的实现是
void User_management_Widget::AddUsers()
{
Add_User_Widget *auw = new Add_User_Widget;
auw->show();//打开增加用户窗口
}
点开后增加用户的窗口(Add_User_Widget
)是这样的
如果我们要新建一个用户,并且在按下增加按钮的时候这个窗口关闭,原本的用户管理的窗口里面自动新增一行新的用户,我们就可以在Add_User_Widget
窗口里面写一个数据变化的信号,并且重写窗口关闭事件,让窗口关闭的时候激活这个信号,然后在用户管理(User_management_Widget
)的窗口里面
代码实现
Add_User_Widget
头文件
public:
void closeEvent(QCloseEvent *);//重写关闭事件
signals:
void DataBase_Changed();//数据改变信号
Add_User_Widget
CPP文件,信号不用写实现
void Add_User_Widget::closeEvent(QCloseEvent *)
{
emit Add_User_Widget::DataBase_Changed();//激活信号
}
User_management_Widget
头文件
public:
void CreateTable();//建立用户表
private slots:
void AddUsers();//增加用户
其中CreateTable()中写创建表格的函数,如果用到了本地sqlite可以这样写:
void User_management_Widget::CreateTable()
{
QString is_admin;//用于储存“管理员”和“普通用户”字符串
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("Trading_Platfrom_database.dat");
if(db.open()){
qDebug()<<"数据库打开成功";
}
QSqlQuery query;
query.prepare("select * from users");
query.exec();
item = new QStandardItemModel;
item->setColumnCount(3);
item->setHeaderData(0,Qt::Horizontal,"ID");
item->setHeaderData(1,Qt::Horizontal,"账户");
item->setHeaderData(2,Qt::Horizontal,"权限");
//ui->information_down->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed);//不允许拖动大小
ui->information_down->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);//自动伸缩
ui->information_down->verticalHeader()->hide();//隐藏行号
ui->information_down->setModel(item);//....
ui->information_down->setAlternatingRowColors( true ); // 可以选择的颜色
ui->information_down->setFrameShape(QFrame::NoFrame);//无边框
typedef struct tableInformation{
QString id;
QString account;
int is_admin;
}table;
int i = 0;
while(query.next()){
table t_in;
t_in.id = query.value("id").toString();
t_in.account =query.value("account").toString();
t_in.is_admin = query.value("is_admin").toInt();
item->setItem(i,0,new QStandardItem(t_in.id));
item->setItem(i,1,new QStandardItem(t_in.account));
if( t_in.is_admin){
is_admin = "管理员";
}else{
is_admin = "普通用户";
}
item->setItem(i,2,new QStandardItem(is_admin));
i++;
qDebug()<<t_in.id<<" 账号 " <<t_in.account <<" 是否是管理 " <<t_in.is_admin;
}
db.close();
}
然后再此窗口的构造函数中需要写信号与槽(添加用户窗口按钮和打开添加用户窗口的信号和槽)
connect(ui->Add_Users,&QPushButton::clicked,this,&User_management_Widget::AddUsers);//增加用户
AddUsers槽函数:
void User_management_Widget::AddUsers()
{
Add_User_Widget *auw = new Add_User_Widget;
auw->show();
connect(auw,&Add_User_Widget::DataBase_Changed,this,[&](){
this->CreateTable();
});
}
其中
connect(auw,&Add_User_Widget::DataBase_Changed,this,[&](){
this->CreateTable();
});
用到了qt lambda表达式,详细请见:
【QT】QT中使用Lambda表达式,作者半生瓜のblog
==========================================================================