day5
事件与绘图
参考https://www.kancloud.cn/kancloud/qt-study-road-2/99458
c++知识点:虚函数-virtual-关键字,它在父类声明,在子类实现。实现动态绑定。
QWidget里面有一些虚函数声明,我们的widget继承了QWidget,所以我们在widget里实现自己的虚函数,参数返回值权限不能改变。
关闭程序时,弹出对话框提示用户是否保存文本
//widget.h
protected:
void closeEvent(QCloseEvent *event);
//widget.cpp
void Widget::closeEvent(QCloseEvent *event)
{
if(QMessageBox::No==QMessageBox::question(this,"退出question","是否保存"))
{//是关闭事件吗?
event->ignore();//忽略关闭事件
qDebug()<<"testing close event";
}
event->accept();//接受关闭事件
}
鼠标事件,点击左键右键,拖动或跟踪
//widget.h
protected:
void mousePressEvent(QMouseEvent *event);
//widget.cpp
void Widget::mousePressEvent(QMouseEvent *event)
{
if(event->button()==Qt::LeftButton)
qDebug()<<"testing mouse left event";
else if(event->button()==Qt::RightButton)
qDebug()<<"testing mouse right event";
qDebug()<<event->x()<<","<<event->y()<<"."<<endl;
}
//widget.h
void mouseMoveEvent(QMouseEvent *event);//鼠标拖动
//widget.cpp
void Widget::mouseMoveEvent(QMouseEvent *event)
{
QDebug()<<"testing mouse move";
}
//鼠标跟踪
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
//startTimer(10);
setMouseTracking(true);//鼠标跟踪功能//不用拖动也能触发mouse move event
}
键盘事件
//widget.h
protected:
void keyPressEvent(QKeyEvent *event);
//widget.cpp
void Widget::keyPressEvent(QKeyEvent *event)
{
switch(event->key())
{
case Qt::Key_A:
qDebug()<<"mouse left event";
break;
case Qt::Key_D:
qDebug()<<"mouse right event";
break;
default:
QWidget::keyPressEvent(event);
}
}
定时器事件
//widget.h
protected:
void timerEvent(QTimerEvent*);
//widget.cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
startTimer(10);
}
void Widget::timerEvent(QTimerEvent *)
{
qDebug()<<"定时...";
}
绘图
//widget.h
protected:
void paintEvent(QPaintEvent*);
//widget.cpp
void Widget::paintEvent(QPaintEvent *)
{
//将窗口部件绘制出来,一开始.show()时肯定会调用
//qDebug()<<"paintEvent";
//最小化隐藏后再次展示,就会再次调用这个事件
QPainter painter(this);//产生画笔
painter.setPen(Qt::red);
painter.drawLine(10,10,200,200);//画一条直线
}
鼠标点击的地方画点。
这时,在鼠标点击的事件里画点报错,于是我们在鼠标点击的事件记录坐标,然后在绘图事件里根据坐标画点。
//void Widget::mousePressEvent(QMouseEvent *event)
/*
x_pos=event->x();//在widiget上画点
y_pos=event->y();
update();//强制重新绘制窗口
*/
//void Widget::paintEvent(QPaintEvent *)
QPainter painter(this);//产生画笔,在widget上画
/*
painter.setPen(Qt::red);
painter.drawLine(10,10,200,200);//画一条直线
*/
//painter.drawPoint(x_pos,y_pos);//只画了一个点,画完会清零
以上做法都是纯新手,在显存上画图,并且在鼠标拖动的事件里画。下面介绍双缓存,内存pixmap->显存widget
//头文件里声明pixmap,鼠标拖动事件,也声明两个坐标量用于mousemove事件和mousepress事件和paint事件
void mouseMoveEvent(QMouseEvent *event);//鼠标拖动
QPixmap pixmap;//图片缓存区,没有*号
int x,y;
//源文件构造函数里声明pixmap
//Widget::Widget(QWidget *parent)
: QWidget(parent)
pixmap=QPixmap(size());//产生一个窗口大小的空间,转换为Qpixmap类型
pixmap.fill(Qt::white);
//void Widget::paintEvent(QPaintEvent *)
QPainter painter(this);//产生画笔
//把pixmap画的图片搬到widget上
painter.drawPixmap(0,0,pixmap);//从(0,0)点开始画
//void Widget::mouseMoveEvent(QMouseEvent *event)
QPainter painter(&pixmap);
painter.setPen(Qt::red);
//painter.drawPoint(event->x(),event->y());//画点会断断续续
painter.drawLine(x,y,event->x(),event->y());
x=event->x();
y=event->y();//更新坐标
update();
//void Widget::mousePressEvent(QMouseEvent *event)
//在一开始鼠标点击的事件里记录坐标初值,传参给paintEvent
x=event->x();
y=event->y();
练习,按下S键绘制正弦曲线,空格键清空窗口
case Qt::Key_S:
double y;
for(int i;i<=360;i++)
{
y=150-100*(qSin(i*pi/180));//坐标系处理
painter.drawPoint(i,y);
}
//QPainter painter(&pixmap);//构造和析构函数不可跳过。如果没按s键,就只析构不构造了
//painter.drawLine(10,10,300,300);
update();
break;
case Qt::Key_Space:
pixmap.fill();
update();
break;
登录界面
UI设计如图
ui设计好后,转到槽,先做注册功能。需要按下按钮,打开一个文件,把两个lineedit的用户和密码输出到文件中。
//注册-把用户名和密码保存到一个文件password.dat里
QFile file("password.dat");//创建文件类对象
//QFilename *filename=get_openfilename();
if(!file.open(QIODevice::ReadWrite))//以读写模式打开
{
QMessageBox::warning(this,"regester","open password err");
return ;
}
QDataStream out(&file);//绑定到数据流out上
QString username,password;
while(!out.atEnd())
{
out>>username>>password;
if(username==ui->lineEdit->text()&&password==ui->lineEdit_2->text())
QMessageBox::warning(this,"regester","you had regestered");
return ;
}
//qDebug()<<"testing register";
//QTextStream out(&file);//文本流,字符连在一起,没有格式
//QDataStream out(&file);//数据流
out<<ui->lineEdit->text()<<ui->lineEdit_2->text();
QMessageBox::information(this,"regester","regester success");
实现登录功能。需要读取注册时保存的文件“password.dat”,与当前lineedit用户输入的字符比较,登录成功弹出对话框。
//登录
QFile file("password.dat");
if(!file.open(QIODevice::ReadOnly))
{
QMessageBox::warning(this,"error","open password err");
return ;
}
QDataStream in(&file);
QString username,password;
while(!in.atEnd())
{
in>>username>>password;
if(username==ui->lineEdit->text()&&password==ui->lineEdit_2->text())
{
QMessageBox::information(this,"login","login success");
/*MainWindow *w=new MainWindow;
w->show();
close();*/
accept();
return ;
}
}
QMessageBox::information(this,"login","login fail");
登录成功后,点击关闭对话框,发出accept信号,然后进入另一个mainwindow窗口
方法1:
在登录函数,判断密码正确的语句后加上accept(),在main.cpp的main()里将原来的非阻塞w.show改成事件循环,并判断接收到的信号是accept()才执行下一句,下一句就是转到另一个mainwindow窗口。
方法2:
登录触发的函数中,注释语句换成注释accept
/*MainWindow *w=new MainWindow;
w->show();
close();*/
accept();
main函数中注释的语句换成注释后面三句话
/* w.show();*/
if (w.exec()==QDialog::Rejected)//这里是事件循环,等待对话框正常关闭发出accepted信号,才执行下一步展示mainwindow
{
return 0;
}
MainWindow m;
m.show();
实验感受
- 改了dialog的名字后出错,非法使用Ui::Dialog,新名字login_obj。注意创建的对象名与操作要匹配。
拓展知识
事件过滤器
https://www.kancloud.cn/kancloud/qt-study-road-2/99460