c++ qt
创建项目:
- widget:普通窗口,控件
- window:可以添加状态栏等
指定父对象
#include<QApplication>
#include<QWidget>
#include<QPushButton>
int main(int argc,char **argv){
QApplication app(argc,argv);
QWidget w;
w.setWindowTitle("ttile");
QPushButton b;
b.setText("^_^");
b.setParent(&w);//指定父对象
b.move(100,0);
QPushButton b1(&w);//指定父对象
b1.setText("abe");
//b1.move(0,100);
b1.setGeometry(0,100,200,200);//x,y,w,h
w.show();
app.exec();
return 0;
}
指定了父对象就会随父对象一起展示,如果没指定就要自己展示,而且独立存在。
标准信号和槽(hard)
- 一个信号可以连接多个槽函数
- 槽函数执行的顺序是随机的,不能控制
- 一个槽函数可以被多个信号连接
- 信号可以连接信号
- 信号槽连接成功后,可以断开连接disconnect
- 槽函数可以是lambda表达式
#include "widget.h"
#include <QPushButton>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
QPushButton *b1 = new QPushButton(this);
b1->setText("b1");
connect(b1,&QPushButton::pressed,this,&QWidget::close);//点击btn关闭窗口
/* 参数1:监听对象
参数2:监听动作(信号)(可自定义)
参数3:哪个对象处理
参数4:怎么处理(槽)(可自定义)
*/
}
自定义槽函数
#include "widget.h"
#include <QPushButton>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
QPushButton *b1 = new QPushButton(this);
b1->setText("b1");
//connect(b1,&QPushButton::pressed,this,&QWidget::close);
connect(b1,&QPushButton::pressed,this,&Widget::mySolt);
}
void Widget::mySolt(){
qDebug()<<"111";
}
先添加成员函数 mySolt
lamda方式:
配置文件 最后先添加:CONFIG += C++11
#-------------------------------------------------
#
# Project created by QtCreator 2023-08-15T19:25:24
#
#-------------------------------------------------
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = 03_again
TEMPLATE = app
SOURCES += main.cpp\
widget.cpp
HEADERS += widget.h
CONFIG += C++11
#include "widget.h"
#include <QPushButton>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
QPushButton *b1 = new QPushButton(this);
b1->setText("b1");
//connect(b1,&QPushButton::pressed,this,&QWidget::close);
//connect(b1,&QPushButton::pressed,this,&Widget::mySolt);
connect(b1,&QPushButton::pressed,[=](){
qDebug()<<"222";
});
}
=
符号是将范围内的所有成员形参形式传入匿名函数,方便里面调用。
- mutable:通过
=
传递的是被const修饰的,是不可改变的,添加 mutable 即可不被const修饰。 - exception:如果想抛出异常需要添加 exception
- -> int:如果有返回值,需要按照这个格式添加
自定义信号
一个窗口控制另一个窗口显示:
创建新窗口,创建自定义信号:
#ifndef SUB_H
#define SUB_H
#include <QWidget>
class sub : public QWidget
{
Q_OBJECT
public:
explicit sub(QWidget *parent = 0);
signals:
void mySignal();//自定义信号
public slots:
void mySolt();//自定义处理函数(槽)
};
#endif // SUB_H
创建按钮并发送自定义信号:
#include "sub.h"
#include <QPushButton>
sub::sub(QWidget *parent) :
QWidget(parent)
{
QPushButton *b2 = new QPushButton(this);
b2->setText("b2");
connect(b2,&QPushButton::released,this,&sub::mySolt);//按钮监听
}
void sub::mySolt(){
emit mySignal();//发送自定义信号
}
第一个窗口引用新窗口:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <sub.h>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
void mySolt();
void mySignalDeal();//处理自定义信号函数
sub s;//新窗口
};
#endif // WIDGET_H
实现展示隐藏另一个窗口功能:
#include "widget.h"
#include <QPushButton>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
resize(300,300);
QPushButton *b1 = new QPushButton(this);
b1->setText("b1");
connect(b1,&QPushButton::pressed,this ,&Widget::mySolt);//本窗口按钮监听
connect(&s,&sub::mySignal,this,&Widget::mySignalDeal);//监听新窗口发送的自定义信号
}
void Widget::mySolt(){//展示新窗口
s.show();
this->hide();
}
void Widget::mySignalDeal(){//处理自定义信号函数
//qDebug()<<"mySignalDeal";
s.hide();
this->show();
}
自定义带参数的信号
创建新窗口,创建自定义信号:
#ifndef SUB_H
#define SUB_H
#include <QWidget>
class sub : public QWidget
{
Q_OBJECT
public:
explicit sub(QWidget *parent = 0);
signals:
void mySignal(int, QString);//自定义信号
public slots:
void mySolt();//自定义处理函数(槽)
};
#endif // SUB_H
创建按钮并发送自定义信号:
#include "sub.h"
#include <QPushButton>
sub::sub(QWidget *parent) :
QWidget(parent)
{
QPushButton *b2 = new QPushButton(this);
b2->setText("b2");
connect(b2,&QPushButton::released,this,&sub::mySolt);//按钮监听
}
void sub::mySolt(){
emit mySignal(5,"test");//发送自定义信号
}
第一个窗口引用新窗口:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <sub.h>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
void mySolt();
void mySignalDeal(int,QString);//处理自定义信号函数
sub s;//新窗口
};
#endif // WIDGET_H
实现展示隐藏另一个窗口功能:
#include "widget.h"
#include <QPushButton>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
resize(300,300);
QPushButton *b1 = new QPushButton(this);
b1->setText("b1");
connect(b1,&QPushButton::pressed,this ,&Widget::mySolt);//本窗口按钮监听
//connect(&s,&sub::mySignal,this,&Widget::mySignalDeal);//监听新窗口发送的自定义信号
void (sub::*fun)(int,QString) = &sub::mySignal;//需要 函数指针 配合
connect(&s,fun,this,&Widget::mySignalDeal);//监听新窗口发送的自定义信号
}
void Widget::mySolt(){//展示新窗口
s.show();
this->hide();
}
void Widget::mySignalDeal(int i,QString str){//处理自定义信号函数
qDebug()<<i<<str;
s.hide();
this->show();
}
菜单栏工具栏等
#include "mainwindow.h"
#include <QMenuBar>
#include <QMenu>
#include <QAction>
#include <QDebug>
#include <QToolBar>
#include <QPushButton>
#include <QStatusBar>
#include <QLabel>
#include <QTextEdit>
#include <QDockWidget>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
//=== menuBar ===
QMenuBar *mBar = menuBar();
//add menu
QMenu *pFile = mBar->addMenu("FIle");
//add menu item
QAction *pNew = pFile->addAction("new");
connect(pNew,&QAction::triggered,[=](){qDebug()<<"11";});//deal
pFile->addSeparator();//devide
QAction *pOpen = pFile->addAction("open");
//=== toolBar ===
QToolBar *toolBar = addToolBar("toolBar");
//add item
toolBar->addAction(pNew);
//add item by widget
QPushButton *b = new QPushButton(this);
b->setText("btn");
connect(b,&QPushButton::clicked,[=](){b->setText("^_^");});
toolBar->addWidget(b);
//=== stateBar ===
QStatusBar *sBar = statusBar();
QLabel *label = new QLabel(this);
label->setText("Normal text file");
sBar->addWidget(label);
sBar->addWidget(new QLabel("label2",this));
sBar->addPermanentWidget(new QLabel("label3",this));
//=== coreControl ===
QTextEdit *textEdit = new QTextEdit(this);
setCentralWidget(textEdit);
//=== floatWindow ===
QDockWidget *dock = new QDockWidget(this);
addDockWidget(Qt::RightDockWidgetArea,dock);
dock->setWidget(new QTextEdit(this));
resize(400,300);
}
MainWindow::~MainWindow()
{
}
模态和非模态对话框
模态对话框:打开时阻塞,不能对后面的主窗口进行操作。
#include "mainwindow.h"
#include <QMenu>
#include <QMenuBar>
#include <QAction>
#include <QDialog>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QMenuBar *mBar = menuBar();
// setMenuBar(mBar);
QMenu *menu = mBar->addMenu("dialog");
QAction *pl = menu->addAction("modalDialog");
connect(pl,&QAction::triggered,[=](){
QDialog dlg;
dlg.resize(100,100);
dlg.exec();
});
QAction *p2 = menu->addAction("Dialog");
connect(p2,&QAction::triggered,[=](){
QDialog *dlg = new QDialog();
dlg->resize(100,100);
dlg->setAttribute(Qt::WA_DeleteOnClose);//close to free
dlg->show();
});
resize(400,300);
}
MainWindow::~MainWindow()
{
}
标准对话框和文件对话框
#include "mainwindow.h"
#include <QMenu>
#include <QMenuBar>
#include <QAction>
#include <QDialog>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QMenuBar *mBar = menuBar();
// setMenuBar(mBar);
QMenu *menu = mBar->addMenu("dialog");
//关于
QAction *p3 = menu->addAction("about");
connect(p3,&QAction::triggered,[=](){
QMessageBox::about(this,"about","about Qt");
});
//问题
QAction *p4 = menu->addAction("question");
connect( p4,&QAction::triggered,[=](){
int ret = QMessageBox::question(this,"question","Are you ok?");
/*You can specify your own buttons
int ret = QMessageBox::question(this,"question","Are you ok?",
QMessageBox::Yes|QMessageBox::No);
*/
switch(ret){
case QMessageBox::Yes:
qDebug()<<"yes";
break;
case QMessageBox::No:
qDebug()<<"no";
break;
default:
break;
}
});
//文件
QAction *p5 = menu->addAction("file");
connect( p5,&QAction::triggered,[=](){
QString path = QFileDialog::getOpenFileName(this,"open","../",
"source(*.cpp *.h *.c );;"
"Text(*.txt);;"
"all(*.*)");
qDebug()<<path;
});
resize(400,300);
}
MainWindow::~MainWindow()
{
}
设计器
常用控件
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QCompleter>
#include <QStringList>
#include <QMovie>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//push button
ui->btn->setText("hhh");
//connect(ui->btn,&QPushButton::clicked,this,&MainWindow::close);
//radio button
ui->radioButton->setText("radio11");
ui->radioButton_2->setChecked(true);
//check box
ui->checkBox->setChecked(true);
ui->checkBox_2->setChecked(true);
//line edit
QString str = ui->lineEdit->text();
qDebug()<<str;
//line edit mode:password
//ui->lineEdit->setEchoMode(QLineEdit::Password);
//line edit hint
QStringList list;
list<<"hell"<<"How are you"<<"fine";
QCompleter *com = new QCompleter(list,this);
com->setCaseSensitivity(Qt::CaseInsensitive);//
ui->lineEdit->setCompleter(com);
//label -> img gif url
ui->label->setText("^_^");
//img
ui->labelImage->setPixmap(QPixmap("://image/OnePiece.png"));
ui->labelImage->setScaledContents(true);
//create movie
QMovie *myMovie = new QMovie("://image/mario.gif");
//set movie to label
ui->labelGif->setMovie(myMovie);
ui->labelGif->setScaledContents(true);
//start movie
myMovie->start();
//url
ui->labelUrl->setText("<a href=\"https://www.baidu.com\">baidu</a>");
ui->labelUrl->setOpenExternalLinks(true);
//lcm Number
ui->lcdNumber->display("hello");
//progressBar
ui->progressBar->setMaximum(100);
ui->progressBar->setMinimum(0);
ui->progressBar->setValue(75);
}
MainWindow::~MainWindow()
{
delete ui;
}
//Stacked Widget change
void MainWindow::on_btn_sw_clicked()
{
static int i = 0;
ui->stackedWidget->setCurrentIndex(++i%2);
}
布局
绝对定位 和 布局定位。
手动拖进去点击布局模式就好。多拉几个容器,分容器内布局,最后总体布局。
自定义控件
创建一个widget:
#include "smallwidget.h"
#include <QSpinBox>
#include <QSlider>
#include <QHBoxLayout>
SmallWidget::SmallWidget(QWidget *parent) :
QWidget(parent)
{
QSpinBox *spin = new QSpinBox(this);
QSlider *slider = new QSlider(Qt::Horizontal,this);
QHBoxLayout *hLayout = new QHBoxLayout(this);
hLayout->addWidget(spin);
hLayout->addWidget(slider);
}
这个控件就会变成自定义控件:
给两个控件 相关联
//interaction
//spin -> slider // 因为QSpinBox的valueChanged方法重载了,有两个,需要类型转化
connect(spin,static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged),
slider,&QSlider::setValue);
//slider -> spin
connect(slider,&QSlider::valueChanged,
spin,&QSpinBox::setValue);
样式表
//css
ui->label->setStyleSheet("QLabel{color:red;}");
ui->label->setStyleSheet("QLabel{color:rgb(0,255,255);"
"background-color:red;"
"border-image:url(:/new/prefixl/image/1.png);"
"}");
ui->gameWidget->setStyleSheet("QWidget{border:1 solid black;}");
//widget内所有 label 元素
this->setStyleSheet(QLabel{..});
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
+ a.setStyleSheet("");//全局
Widget w;
w.show();
return a.exec();
}
伪状态
ui->btn->setStyleSheet("QPushButton{"
"border-image:url(:/new/prefixl/image/1.png);"
"}"
"QPushButton:hover{"
"border-image:url(:/new/prefixl/image/up.png);"
"}"
"QPushButton:pressed{"
"border-image:url(:/new/prefixl/image/click.png);"
"}"
);
事件
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QMouseEvent>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
protected:
//鼠标事件
void mousePressEvent(QMouseEvent *);
void mouseReleaseEvent(QMouseEvent *);
void mouseMoveEvent(QMouseEvent *);
//进入、离开 窗口
void enterEvent(QEvent *);
void leaveEvent(QEvent *);
//键盘事件
void keyPressEvent(QKeyEvent *);
//定时器事件
void timerEvent(QTimerEvent *);
private:
Ui::Widget *ui;
int timerId;
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
//css
ui->label->setStyleSheet("QLabel{color:rgb(0,255,255);"
"background-color:red;"
"background-image:url()"
"}");
//set trace mouse
this->setMouseTracking(true);
//start timer
timerId = this->startTimer(1000);//ms
//key press 多个widget时,需要监听的widget要写这个。
setFocusPolicy(Qt::StrongFocus);
}
void Widget::mousePressEvent(QMouseEvent *ev){
qDebug()<<"111";
int x = ev->x();
int y = ev->y();
QString str;
/*
if(ev->button()==Qt::LeftButton){
str = QString("left:%1 %2").arg(x).arg(y);
}else if(ev->button()==Qt::RightButton){
str = QString("right:%1 %2").arg(x).arg(y);
}else if(ev->button()==Qt::MiddleButton){
str = QString("mid:%1 %2").arg(x).arg(y);
}else{*/
str = QString("other:%1 ").arg(ev->button());
// }
//qDebug()<<str;
ui->label->setText(str);
}
void Widget::mouseReleaseEvent(QMouseEvent *ev){
qDebug()<<"222";
}
void Widget::mouseMoveEvent(QMouseEvent *ev){
int x = ev->x();
int y = ev->y();
QString str;
str = QString("mid:%1 %2").arg(x).arg(y);
ui->label->setText(str);
}
void Widget::enterEvent(QEvent *e){
ui->label->setText("enterEvent");
}
void Widget::leaveEvent(QEvent *e){
ui->label->setText("leaveEvent");
}
void Widget::keyPressEvent(QKeyEvent *e){
QString str;
str = QString("key:%1").arg((char)e->key());
ui->label->setText(str);
}
void Widget::timerEvent(QTimerEvent *e){
//定时器可以定义多个。
if(e->timerId()==this->timerId){
static int sec = 0;
QString str;
str = QString("timer:%1").arg(sec++);
ui->label->setText(str);
//cloae if 5sec
if(sec==5){
this->killTimer(timerId);
}
}
}
Widget::~Widget()
{
delete ui;
}
事件的接收和忽略
重写点击事件,事件拦截,自定义按钮继承QPushbutton
#ifndef MYBUTTON_H
#define MYBUTTON_H
#include <QWidget>
#include <QPushButton>
class myButton : public QPushButton
{
Q_OBJECT
public:
explicit myButton(QWidget *parent = 0);
protected:
void mousePressEvent(QMouseEvent *e);
signals:
public slots:
};
#endif // MYBUTTON_H
#include "mybutton.h"
#include <QMouseEvent>
#include <QDebug>
myButton::myButton(QWidget *parent) :
QPushButton(parent)
{
}
//重写点击事件
void myButton::mousePressEvent(QMouseEvent *e){
if(e->button()==Qt::LeftButton){//如果是左键点击,拦截事件
qDebug()<<"222";
}else{//点击 空格,继续传递事件
QPushButton::mouseMoveEvent(e);
}
}
main.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QDebug>
#include <QMessageBox>
#include <QCloseEvent>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
ui->pushButton->setText("hh");
connect(ui->pushButton,&QPushButton::pressed,[=](){
qDebug()<<"111";
});
}
Widget::~Widget()
{
delete ui;
}
接收 或 忽略:
监听点击关闭按钮事件:
void closeEvent(QCloseEvent *);
void Widget::closeEvent(QCloseEvent *e){
int ret = QMessageBox::question(this,"quer","do you close window?");
if(ret==QMessageBox::Yes){
qDebug()<<"yes";
e->accept();//事件的传递
}else{
qDebug()<<"no";
e->ignore();//事件的忽略,如果没有这行,就算选no也会关闭窗口
}
}
event()函数
每个控件都有event()函数,通过这个函数分发具体的事件函数。
bool event(QEvent *);
bool Widget::event(QEvent *e){
//事件分发
switch(e->type()){
case QEvent::Close:
qDebug()<<"event->Close";
QCloseEvent *env = static_cast< QCloseEvent *>(e);
Widget::closeEvent(env);
return true;
}
if(e->type()==QEvent::Timer){//屏蔽定时器
return true;
}else if(e->type()==QEvent::KeyPress){//屏蔽非按键B
QKeyEvent *env = static_cast< QKeyEvent *>(e);
if(env->key()==Qt::Key_B){
return QWidget::event(e);
}
return true;
}
return QWidget::event(e);//一定要返回其他事件,否则其他事件都无法下发。
}
事件过滤器
每个控件都有单独的event函数,如果想一次性屏蔽多个控件的某些event事件,需要用到:
bool eventFilter(QObject *, QEvent *);
来自QObject 最终基类。
bool eventFilter(QObject *, QEvent *);
#include <QDebug>
#include <QMessageBox>
#include <QCloseEvent>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
//安装过滤器
ui->label->installEventFilter(this);
}
bool Widget::eventFilter(QObject *obj, QEvent *e){
//判断控件
if(obj==ui->label){
//判断事件
if(e->type()==QEvent::MouseMove){
ui->label->setText("filter");
return true;
}
}
return QWidget::eventFilter(obj,e);//一定要返回其他事件
}
注意:事件过滤器和被安装过滤器的组件必须在同一个线程里面,否则无效。
如果在安装过滤器之后,这两个组件到了不同的线程,那么只能等到二者重新回到同一个线程的时候过滤器才生效。
绘图
画背景图
protected:
//重新绘图事件,虚函数
//如果在窗口绘图,必须放在绘图事件里实现
//绘图事件内部自动调用,窗口需要重绘的时候(状态改变)
void paintEvent(QPaintEvent *);
void Widget::paintEvent(QPaintEvent *e){
//QPainter p(this);
QPainter p;//创建画家对象
p.begin(this);//指定当前窗口为绘图设备
//画背景图
//p.drawPixmap(0,0,width(),height(),QPixmap("../Image/bk.jpg"));
p.drawPixmap(rect(),QPixmap("../Image/bk.jpg"));
p.end();
}
简单绘图
#include "widget.h"
#include "ui_widget.h"
#include <QPainter>//画家
#include <QPen>//画笔
#include <QBrush>//画刷
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
}
void Widget::paintEvent(QPaintEvent *e){
//QPainter p(this);
QPainter p;//创建画家对象
p.begin(this);//指定当前窗口为绘图设备
//画背景图
//p.drawPixmap(0,0,width(),height(),QPixmap("../Image/bk.jpg"));
p.drawPixmap(rect(),QPixmap("../Image/bk.jpg"));
//定义画笔
QPen pen;
pen.setWidth(5);//设置线宽
//pen.setColor(Qt::red);//颜色
pen.setColor(QColor(161,242,141));//颜色
pen.setStyle(Qt::DashLine);//设置风格
//把画笔给画家
p.setPen(pen);
//画直线
p.drawLine(50,50,150,50);
p.drawLine(50,50,50,150);
//画刷
QBrush brush;
brush.setColor(Qt::yellow);
brush.setStyle(Qt::Dense1Pattern);
p.setBrush(brush);
//画矩形
p.drawRect(100,100,150,50);
//画圆
p.drawEllipse(QPoint(150,150),50,25);
p.end();
}
Widget::~Widget()
{
delete ui;
}
手动更新窗口
//刷新窗口,整个窗口都重绘
update();//间接调用paintEvent()
//刷新局部
update(0,200,width(),height()-200);
注意:不要放到paintEvent()函数里面,不然会无限递归循环,程序会很卡,崩掉。
QBitmap 和 QPixmap 区别
QBitmap 只显示黑白两种颜色,占用内存小
#include <QPainter>
#include <QBitmap>
void Widget::paintEvent(QPaintEvent *e){
QPainter p(this);
//背景透明
p.drawPixmap(0,0,QPixmap("../Image/butterfly.png"));
p.drawPixmap(200,0,QBitmap("../Image/butterfly.png"));
//背景白色
QPixmap pixmap;
pixmap.load("../Image/butterfly1.png");
p.drawPixmap(0,200,pixmap);
QBitmap bixmap;
bixmap.load("../Image/butterfly1.png");
p.drawPixmap(200,200,bixmap);
}
绘图设备
- QPixmap:针对屏幕进行优化,和平台相关,不能对图片进行修改
- QImage:和平台无关,可以对图片进行修改,在线程中绘图
- QPicture:保存绘图的状态(二进制文件)
QPixmap:
#include "widget.h"
#include "ui_widget.h"
#include<QPainter>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
//不在窗口内画图
//绘图设备400x300
QPixmap pixmap(400,300);
QPainter p(&pixmap);
//填充背景色
pixmap.fill(Qt::white);
//p.fillRect(0,0,400,300,QBrush(Qt::white));
p.drawPixmap(0,0,80,80,QPixmap("../Image/face.png"));
//保存图片
pixmap.save("../Image/pixmap17.png");
}
Widget::~Widget()
{
delete ui;
}
QImage:
#include "widget.h"
#include "ui_widget.h"
#include<QPainter>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
//可指定背景透明。
QImage image(400,300,QImage::Format_ARGB32);
QPainter p;
p.begin(&image);
//绘图
p.drawImage(0,0,QImage("../Image/face.png"));
//对绘图设备前50个像素点进行操作
for(int i=0;i<50;i++){
for(int j=0;j<50;j++){
image.setPixel(QPoint(i,j),qRgb(0,0,255));
//获取像素点的rgb
//image.pixel(QPoint(i,j));
}
}
p.end();
image.save("../Image/image17.png");
}
Widget::~Widget()
{
delete ui;
}
QPicture:
#include "widget.h"
#include "ui_widget.h"
#include <QPainter>
#include <QPicture>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
QPicture picture;
QPainter p;
p.begin(&picture);
p.drawPixmap(0,0,80,80,QPixmap("../Image/face.png"));
p.drawLine(50,50,150,50);
p.end();
picture.save("../Image/picture17.png");
//保存的 是二进制文件 无法直接打开
}
void Widget::paintEvent(QPaintEvent *){
//打开保存的二进制文件
QPicture pic;
pic.load("../Image/picture17.png");
QPainter p(this);
p.drawPicture(0,0,pic);
}
Widget::~Widget()
{
delete ui;
}
QImage 和 QPixmap 相互转换
各个设备有各自的优势:显示好,传输快。
void Widget::paintEvent(QPaintEvent *){
QPainter p(this);
QPixmap pixmap;
pixmap.load("../Image/face.png");
//QPixmap -> QImage
QImage tempImage = pixmap.toImage();
p.drawImage(0,0,tempImage);
QImage image;
image.load("../Image/face.png");
//QImage -> QPixmap
QPixmap tempPixmap = QPixmap::fromImage(image);
p.drawPixmap(100,0,tempPixmap);
}
不规则窗口
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
protected:
void paintEvent(QPaintEvent *);
void mousePressEvent(QMouseEvent *);
void mouseMoveEvent(QMouseEvent *);
private:
Ui::Widget *ui;
QPoint p;
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
#include<QPainter>
#include<QMouseEvent>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
//去窗口表栏
setWindowFlags(Qt::FramelessWindowHint|windowFlags());
//把窗口背景色设置为透明
setAttribute(Qt::WA_TranslucentBackground);
}
//绘画背景透明图片
void Widget::paintEvent(QPaintEvent *){
QPainter p(this);
p.drawPixmap(0,0,QPixmap("../Image/sunny.png"));
}
//按下时:右键关闭;左键获取点击的图标并计算出左上角图标
void Widget::mousePressEvent(QMouseEvent *e){
if(e->button()==Qt::RightButton){
close();//右键关闭
}else if(e->button()==Qt::LeftButton){
//求坐标差
//当前点击坐标 - 窗口左上角坐标
p = e->globalPos() - this->frameGeometry().topLeft();
}
}
//左键点击移动时,更新左上角的坐标。
void Widget::mouseMoveEvent(QMouseEvent *e){
//判断是不是按住左键
if(e->buttons() & Qt::LeftButton){
move(e->globalPos()-p);
}
}
Widget::~Widget()
{
delete ui;
}
QFile
QFile读文件
#include "widget.h"
#include "ui_widget.h"
#include<QFile>
#include<QFileDialog>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_btn_read_clicked()
{
QString path = QFileDialog::getOpenFileName(this,
"open","../","TXT(*.txt)");
if(path.isEmpty()==false){
//文件对象
QFile file(path);
int ret = file.open(QIODevice::ReadOnly);
if(ret == true){
QByteArray array;
#if 0
//一次性读文件 默认格式utf8编码
array = file.readAll();
#endif
//一行行读文件
while(file.atEnd()==false){
//读一行
array += file.readLine();
}
ui->textEdit->setText(QString(array));
}
file.close();//关闭文件
}
}
QFile写文件
void Widget::on_btn_write_clicked()
{
QString path = QFileDialog::getSaveFileName(this,
"save","../","TXT(*.txt)");
if(path.isEmpty()==false){
QFile file;//创建文件对象
file.setFileName(path);//关联文件名字
//打开方式,只写方式
bool isOk = file.open(QIODevice::WriteOnly);
if(isOk==true){
//获取编辑器内容
QString str = ui->textEdit1->toPlainText();
//写文件
//QString -> QByteArray
file.write(str.toUtf8());
//QString -> c++ string -> char *
//file.write(str.toStdString().data());
///转化为本地平台编码
//file.write(str.toLocal8Bit());
}
file.close();
}
}
QFileInfo获取文件信息
#include<QFileInfo>
#include<QDebug>
#include<QDateTime>
QFileInfo info(path);
qDebug()<<"文件名字:"<<info.fileName().toUtf8().data();
qDebug()<<"文件后缀:"<<info.suffix();
qDebug()<<"文件大小:"<<info.size();
qDebug()<<"文件创建时间:"<<
info.created().toString("yyyy-MM-dd hh:mm:ss");//2020-01-01 15:15:00
QDataStream读写文件
二进制方式读写。
void Widget::writeData(){
//创建文件对象
QFile file("../test.txt");
bool isOk = file.open(QIODevice::WriteOnly);
if(true==isOk){
//创建数据流,和file文件关联
//忘数据流中写数据,相当于往文件里写数据
QDataStream stream(&file);
stream<<QString("hello QDataStream")<<250;
file.close();
}
}
void Widget::readData(){
//创建文件对象
QFile file("../test.txt");
bool isOk = file.open(QIODevice::ReadOnly);
if(true==isOk){
//创建数据流,和file文件关联
//忘数据流中读数据,相当于往文件里读数据
QDataStream stream(&file);
//读的时候,按写的顺序取数据
QString str;
int a;
stream >> str >> a;
qDebug()<< str.toUtf8().data() << a;
file.close();
}
}
QTextStream操作文件
文本方式读写。
void Widget::writeData(){
QFile file;
file.setFileName("../demo.txt");
bool isOk = file.open(QIODevice::WriteOnly);
if(true==isOk){
QTextStream stream(&file);
//指定编码,默认按照平台的编码
stream.setCodec("UTF-8");
stream<<QString("hlo QTextStream")<<200;
file.close();
}
}
void Widget::readData(){
QFile file;
file.setFileName("../demo.txt");
bool isOk = file.open(QIODevice::ReadOnly);
if(true==isOk){
QTextStream stream(&file);
//指定编码,默认按照平台的编码
stream.setCodec("UTF-8");
//read 距离识别会出错
QString str;
int a;
stream >> str >> a;
cout << str.toUtf8().data() << a;
file.close();
}
}
QBuffer
和文件关系不大,内存文件。
#include "widget.h"
#include "ui_widget.h"
#include<QBuffer>
#include<QDebug>
#define cout qDebug() << "[" << __FILE__ << ":" << __LINE__ << "]"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
QByteArray array;
QBuffer memFile(&array);//创建内存文件
memFile.open(QIODevice::WriteOnly);
memFile.write("1111 ");
memFile.write("22222");
memFile.close();
cout<<memFile.buffer();
cout<<"array:"<<array;
// 2
QBuffer memFile1;
memFile1.open(QIODevice::WriteOnly);
QDataStream stream(&memFile1);
stream << QString("test") <<340;
memFile1.close();
cout << memFile1.buffer();//读不到
memFile1.open(QIODevice::ReadOnly);
QDataStream in;
in.setDevice(&memFile1);
QString str;
int a;
in >> str >> a;
memFile1.close();
cout<< str << a;
}
Widget::~Widget()
{
delete ui;
}
TCP通信
例子:
QT += network
服务器:
#ifndef SERVERWIDGET_H
#define SERVERWIDGET_H
#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
QT_BEGIN_NAMESPACE
namespace Ui { class ServerWidget; }
QT_END_NAMESPACE
class ServerWidget : public QWidget
{
Q_OBJECT
public:
ServerWidget(QWidget *parent = nullptr);
~ServerWidget();
private slots:
void on_btnSend_clicked();
void on_btnClose_clicked();
private:
Ui::ServerWidget *ui;
QTcpServer *tcpServer;
QTcpSocket *tcpSocket;
};
#endif // SERVERWIDGET_H
#include "serverwidget.h"
#include "ui_serverwidget.h"
ServerWidget::ServerWidget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::ServerWidget)
{
ui->setupUi(this);
setWindowTitle("服务器:8888");
tcpServer = NULL;
tcpSocket = NULL;
//监听套接字,指定父对象,让其自动回收空间
tcpServer = new QTcpServer(this);
tcpServer->listen(QHostAddress::Any,8888);
connect(tcpServer,&QTcpServer::newConnection,[=](){
//取出建立好的连接的套接字
tcpSocket = tcpServer->nextPendingConnection();
//获取对方的IP和端口
QString ip = tcpSocket->peerAddress().toString();
quint16 port = tcpSocket->peerPort();
QString temp = QString("[%1:%2]:成功连接").arg(ip).arg(port);
ui->textEditRead->setText(temp);
connect(tcpSocket,&QTcpSocket::readyRead,[=](){
//从通信套接字中取出内容
QByteArray array = tcpSocket->readAll();
ui->textEditRead->append(array);
});
});
}
ServerWidget::~ServerWidget()
{
delete ui;
}
void ServerWidget::on_btnSend_clicked()
{
if(NULL==tcpSocket) return;
//获取编辑区内容
QString str = ui->textEditWrite->toPlainText();
//给对方发送数据,使用套接字是tcpSocket
tcpSocket->write(str.toUtf8().data());
}
void ServerWidget::on_btnClose_clicked()
{
if(NULL==tcpSocket) return;
//主动和客户端端口断开连接
tcpSocket->disconnectFromHost();
tcpSocket->close();
}
客户端:
#ifndef CLIENTWIDGET_H
#define CLIENTWIDGET_H
#include <QWidget>
#include <QTcpSocket>
namespace Ui {
class ClientWidget;
}
class ClientWidget : public QWidget
{
Q_OBJECT
public:
explicit ClientWidget(QWidget *parent = nullptr);
~ClientWidget();
private slots:
void on_btnConnect_clicked();
void on_btnSend_clicked();
void on_btnClose_clicked();
private:
Ui::ClientWidget *ui;
QTcpSocket *tcpSocket;
};
#endif // CLIENTWIDGET_H
#include "clientwidget.h"
#include "ui_clientwidget.h"
ClientWidget::ClientWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::ClientWidget)
{
ui->setupUi(this);
setWindowTitle("客户端");
tcpSocket = NULL;
tcpSocket = new QTcpSocket(this);
connect(tcpSocket,&QTcpSocket::connected,[=](){
ui->textEditRead->setText("成功和服务器连接");
});
connect(tcpSocket,&QTcpSocket::readyRead,[=](){
//获取对方发送的内容
QByteArray array = tcpSocket->readAll();
//追加到编辑区
ui->textEditRead->append(array);
});
}
ClientWidget::~ClientWidget()
{
delete ui;
}
void ClientWidget::on_btnConnect_clicked()
{
//获取服务器IP端口
QString ip = ui->lineEditIP->text();
qint16 port = ui->lineEditPort->text().toInt();
//主动和服务器建立连接
tcpSocket->connectToHost(QHostAddress(ip),port);
}
void ClientWidget::on_btnSend_clicked()
{
if(NULL==tcpSocket) return;
//获取编辑框内容
QString str = ui->textEditWrite->toPlainText();
//发送数据
tcpSocket->write(str.toUtf8().data());
}
void ClientWidget::on_btnClose_clicked()
{
if(NULL==tcpSocket) return;
tcpSocket->disconnectFromHost();
tcpSocket->close();
}
显示两个窗口:main.cpp
#include "serverwidget.h"
#include "clientwidget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ServerWidget w;
w.show();
ClientWidget c;
c.show();
return a.exec();
}
out:
UDP通信
例子:
QT += network
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include<QUdpSocket>//UDP套接字
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
void dealMsg();//槽函数,处理对方发过来的数据
private slots:
void on_btnSend_clicked();
void on_btnClose_clicked();
private:
Ui::Widget *ui;
QUdpSocket *udpSocket;
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
#include<QHostAddress>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
setWindowTitle("服务器8888");
//分配空间,指定父对象
udpSocket = new QUdpSocket(this);
//绑定
udpSocket->bind(8888);
//当对方成功发送数据过来
//自动触发,readyRead()
connect(udpSocket,&QUdpSocket::readyRead,this,&Widget::dealMsg);
}
void Widget::dealMsg(){
//读取对方发送的内容
char buf[1024] = {0};
QHostAddress cliAddr;//对方地址
quint16 port;//对方端口
qint64 len = udpSocket->readDatagram(buf,sizeof(buf),&cliAddr,&port);
if(len>0){
//格式化
QString str = QString("[%1:%2[] %3")
.arg(cliAddr.toString())
.arg(port)
.arg(buf);
//给编辑区设置内容
ui->textEdit->setText(str);
}
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_btnSend_clicked()
{
//先获取对方的ip和端口
QString ip = ui->lineEditIP->text();
qint16 port = ui->lineEditPort->text().toInt();
//获取编辑区内容
QString str = ui->textEdit->toPlainText();
//给指定的IP发送数据
udpSocket->writeDatagram(str.toUtf8(),QHostAddress(ip),port);
}
void Widget::on_btnClose_clicked()
{
}
可以和其他人的程序连接。
UDP多播组播
去到局域网发送 广播 。
组播:
#include "widget.h"
#include "ui_widget.h"
#include<QHostAddress>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
setWindowTitle("服务器8888");
//分配空间,指定父对象
udpSocket = new QUdpSocket(this);
//绑定
//udpSocket->bind(8888);
udpSocket->bind(QHostAddress::AnyIPv4,8888);
//加入某个组播
//组播地址是D类地址
udpSocket->joinMulticastGroup(QHostAddress("224.0.0.2"));
//udpSocket->leaveMulticastGroup(QHostAddress("224.0.0.2"));//退出组播
//当对方成功发送数据过来
//自动触发,readyRead()
connect(udpSocket,&QUdpSocket::readyRead,this,&Widget::dealMsg);
}
void Widget::dealMsg(){
//读取对方发送的内容
char buf[1024] = {0};
QHostAddress cliAddr;//对方地址
quint16 port;//对方端口
qint64 len = udpSocket->readDatagram(buf,sizeof(buf),&cliAddr,&port);
if(len>0){
//格式化
QString str = QString("[%1:%2[] %3")
.arg(cliAddr.toString())
.arg(port)
.arg(buf);
//给编辑区设置内容
ui->textEdit->setText(str);
}
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_btnSend_clicked()
{
//先获取对方的ip和端口
QString ip = ui->lineEditIP->text();
qint16 port = ui->lineEditPort->text().toInt();
//获取编辑区内容
QString str = ui->textEdit->toPlainText();
//给指定的IP发送数据
udpSocket->writeDatagram(str.toUtf8(),QHostAddress(ip),port);
}
void Widget::on_btnClose_clicked()
{
}
加入某个组播,绑定端口时要使用 ipv4 .
QTimer定时器
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include<QTimer>//定时器对象
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_btnStart_clicked();
void on_btnStop_clicked();
private:
Ui::Widget *ui;
QTimer *myTimer;
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
myTimer = new QTimer(this);
connect(myTimer,&QTimer::timeout,[=](){
static int i =0;
i++;
ui->lcdNumber->display(i);
});
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_btnStart_clicked()
{
//如果定时器没有激活,才启动
if(myTimer->isActive()==false){
//启动定时器
//时间间隔100ms
//每隔100ms,定时器myTimer自动触发timeout()
myTimer->start(100);
}
}
void Widget::on_btnStop_clicked()
{
//如果定时器已经激活,才关闭
if(myTimer->isActive()==true){
myTimer->stop();
}
}
每间隔多少ms就会发送一个 timeout 信号。
TCP传文件
例子:
服务器端:
#ifndef SERVERWIDGET_H
#define SERVERWIDGET_H
#include <QWidget>
#include<QTcpServer>//监听套接字
#include<QTcpSocket>//通信套接字
#include<QFile>
#include<QTimer>
QT_BEGIN_NAMESPACE
namespace Ui { class ServerWidget; }
QT_END_NAMESPACE
class ServerWidget : public QWidget
{
Q_OBJECT
public:
ServerWidget(QWidget *parent = nullptr);
~ServerWidget();
void sendData();//发送文件
private slots:
void on_btnFile_clicked();
void on_btnSend_clicked();
private:
Ui::ServerWidget *ui;
QTcpServer *tcpServer;
QTcpSocket *tcpSocket;
QFile file;
QString fileName;
qint64 fileSize;
qint64 sendSize;
QTimer timer;
};
#endif // SERVERWIDGET_H
#include "serverwidget.h"
#include "ui_serverwidget.h"
#include<QFileDialog>
#include<QFileInfo>
#include<QDebug>
#define cout qDebug() << "[" << __FILE__ << ":" << __LINE__ << "]"
ServerWidget::ServerWidget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::ServerWidget)
{
ui->setupUi(this);
ui->btnFile->setEnabled(false);
ui->btnSend->setEnabled(false);
tcpServer = new QTcpServer(this);
tcpServer->listen(QHostAddress::Any,8888);
connect(tcpServer,&QTcpServer::newConnection,[=](){
tcpSocket = tcpServer->nextPendingConnection();
QString ip = tcpSocket->peerAddress().toString();
quint16 port = tcpSocket->peerPort();
QString str = QString("[%1:%2]:成功连接").arg(ip).arg(port);
ui->textEdit->setText(str);
ui->btnFile->setEnabled(true);
connect(tcpSocket,&QTcpSocket::readyRead,[=](){
//取客户端的信息
QByteArray buf = tcpSocket->readAll();
if(QString(buf).contains("file done")){
//文件接收完毕
ui->textEdit->append("文件发送完毕22");
file.close();
//断开客户端端口
tcpSocket->disconnectFromHost();
tcpSocket->close();
}else{
//ui->textEdit->append("文件传输:"+buf);
cout<<"out:"<<buf;
}
});
});
connect(&timer,&QTimer::timeout,[=](){
//关闭定时器
timer.stop();
//发送文件
sendData();
});
}
ServerWidget::~ServerWidget()
{
delete ui;
}
void ServerWidget::on_btnFile_clicked()
{
QString filePath = QFileDialog::getOpenFileName(this,"open","../");
if(false==filePath.isEmpty()){
fileName.clear();
fileSize = 0;
QFileInfo info(filePath);
fileName = info.fileName();
fileSize = info.size();
cout<<"fileName:"<<fileName;
cout<<"fileSize:"<<fileSize;
sendSize = 0;
file.setFileName(filePath);
bool isOk = file.open(QIODevice::ReadOnly);
if(false==isOk){
cout<<"文件打开失败";
}
ui->textEdit->append(filePath);
ui->btnFile->setEnabled(false);
ui->btnSend->setEnabled(true);
}else{
cout<<"文件路径为空";
}
}
//发送文件按钮
void ServerWidget::on_btnSend_clicked()
{
//先发送文件头信息 文件名##文件大小
QString head = QString ("%1##%2").arg(fileName).arg(fileSize);
//发送头部信息
qint64 len = tcpSocket->write(head .toUtf8());
if(len>0){//头部信息发送成功
//发送真正的文件信息
//防止TCP黏包文件
//需要通过定时器延时 20 ms
timer.start(20);
}else{
cout<<"头部信息发送失败";
file.close();
ui->btnFile->setEnabled(true);
ui->btnSend->setEnabled(false);
}
}
void ServerWidget::sendData(){
qint64 len = 0;
do{
//每次发数据的大小
char buf[4*1024] = {0};
len = 0;
//往文件中读数据
len = file.read(buf,sizeof(buf));
//发送数据,读多少,发多少
len = tcpSocket->write(buf,len);
//发送的数据需要积累
sendSize += len;
//cout<<"sendSize:"<<sendSize;
}while( len>0 );
//是否发送文件完毕
/*
if(sendSize == fileSize){
ui->textEdit->append("文件发送完毕");
file.close();
//把客户端端口
tcpSocket->disconnectFromHost();
tcpSocket->close();
}*/
}
客户端:
#ifndef CLIENTWIDGET_H
#define CLIENTWIDGET_H
#include <QWidget>
#include<QTcpSocket>
#include<QFile>
namespace Ui {
class ClientWidget;
}
class ClientWidget : public QWidget
{
Q_OBJECT
public:
explicit ClientWidget(QWidget *parent = nullptr);
~ClientWidget();
private slots:
void on_btnConnect_clicked();
private:
Ui::ClientWidget *ui;
QTcpSocket *tcpSocket;
QFile file;
QString fileName;
qint64 fileSize;
qint64 recvSize;
bool isStart;
};
#endif // CLIENTWIDGET_H
#include "clientwidget.h"
#include "ui_clientwidget.h"
#include<QMessageBox>
#include<QDebug>
#define cout qDebug() << "[" << __FILE__ << ":" << __LINE__ << "]"
ClientWidget::ClientWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::ClientWidget)
{
ui->setupUi(this);
ui->progressBar->setValue(0);
tcpSocket = new QTcpSocket(this);
isStart = true;
connect(tcpSocket,&QTcpSocket::readyRead,[=](){
//取出接收的内容
QByteArray buf = tcpSocket->readAll();
if(true==isStart){
//接收头
isStart = false;
//解析头部信息
//QString buf = "hello##1024"
//buf.section("##",0,0);
//初始化
fileName = QString(buf).section("##",0,0);
fileSize = QString(buf).section("##",1,1).toInt();
recvSize = 0;
cout<<"client-fileName:"<<fileName;
cout<<"client-fileSize:"<<fileSize;
//打开文件
file.setFileName(fileName);
bool isOk = file.open(QIODevice::WriteOnly);
if(false==isOk){
cout<<"WriteOnly error";
tcpSocket->disconnectFromHost(); //断开连接
tcpSocket->close();
return ;
}
//弹出对话框,显示接收文件的信息
//QString str = QString("接收的文件:[%1:%2kb]").arg(fileName).arg(fileSize/1024);
//QMessageBox::information(this,"文件信息",str);
//设置进度条
ui->progressBar->setMaximum(fileSize/1024);
ui->progressBar->setMinimum(0);
ui->progressBar->setValue(0);
}else{
//文件信息
qint64 len = file.write(buf);
//cout<<"len:"<<len;
//cout<<"buf.size:"<<buf.size();
if(len>0){
recvSize += len;
//cout<<len;
//客户端接收多少,就告诉服务端多少
QString str = QString::number(recvSize);
tcpSocket->write(str.toUtf8().data());
}
//cout<<"client-fileSize:"<<fileSize;
//cout<<"client-recvSize:"<<recvSize;
//更新进度条
ui->progressBar->setValue(recvSize/1024);
if(recvSize == fileSize){
//先给服务器发送 接收文件完成的信息
tcpSocket->write("file done");
file.close();
QMessageBox::information(this,"完成","文件接收完成");
tcpSocket->disconnectFromHost();
tcpSocket->close();
}
}
});
}
ClientWidget::~ClientWidget()
{
delete ui;
}
void ClientWidget::on_btnConnect_clicked()
{
QString ip = ui->lineEditIP->text();
quint16 port = ui->lineEditPort->text().toInt();
tcpSocket->connectToHost(QHostAddress(ip),port);
isStart = true;
//设置进度条
ui->progressBar->setValue(0);
}
线程(bug)
例子:
mywidget
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QWidget>
#include<QTimer>
#include "mythread.h" //线程头文件
QT_BEGIN_NAMESPACE
namespace Ui { class MyWidget; }
QT_END_NAMESPACE
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget *parent = nullptr);
~MyWidget();
void dealTimeOut();
void dealDone();
void stopThread();
private slots:
void on_pushButton_clicked();
private:
Ui::MyWidget *ui;
QTimer *myTimer;
MyThread *thread;
};
#endif // MYWIDGET_H
#include "mywidget.h"
#include "ui_mywidget.h"
#include<QThread>
#include<QDebug>
#define cout qDebug() << "[" << __FILE__ << ":" << __LINE__ << "]"
MyWidget::MyWidget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::MyWidget)
{
ui->setupUi(this);
myTimer = new QTimer(this);
connect(myTimer,&QTimer::timeout,this,&MyWidget::dealTimeOut);
//分配空间
thread = new MyThread(this);
//接收数据处理完的信号
connect(thread,&MyThread::isDone,this, &MyWidget::dealDone);
//关闭窗口时,关闭启动的线程
connect(this,&MyWidget::destroyed,this,&MyWidget::stopThread);
}
void MyWidget::dealTimeOut(){
static int i = 0;
i++;
ui->lcdNumber->display(i);
}
void MyWidget::dealDone(){
cout<<"it is over";
myTimer->stop();
}
void MyWidget::stopThread(){
//停止线程
thread->quit();
thread->wait();
}
MyWidget::~MyWidget()
{
delete ui;
}
void MyWidget::on_pushButton_clicked()
{
if(myTimer->isActive()==false){
myTimer->start(100);
}
#if 0
//非常复杂的数据处理,耗时较长
QThread::sleep(5);
//处理完数据后,关闭定时器
myTimer->stop();
cout<<"out";
#endif
//启动线程,处理数据
thread->start();
}
mythread
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = nullptr);
protected:
//QThread 的 虚函数
//线程处理函数
//不能直接调用,通过start()间接调用
void run();
signals:
void isDone();
};
#endif // MYTHREAD_H
#include "mythread.h"
MyThread::MyThread(QObject *parent)
: QThread{parent}
{
}
void MyThread::run(){
//非常复杂的数据处理,耗时较长
//需要耗时5s
sleep(5);
//处理完数据后发送信号
emit isDone();
}
第二种方式:
mywidget
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QWidget>
#include "mythread.h"
#include <QThread>
#include <QCloseEvent>
QT_BEGIN_NAMESPACE
namespace Ui { class MyWidget; }
QT_END_NAMESPACE
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget *parent = nullptr);
~MyWidget();
void dealSignal();
void dealClose();
protected:
void closeEvent(QCloseEvent *);
signals:
void startThread();//启动子线程的信号
private slots:
void on_btnStart_clicked();
void on_btnStop_clicked();
private:
Ui::MyWidget *ui;
MyThread *myT;
QThread *thread;
};
#endif // MYWIDGET_H
#include "mywidget.h"
#include "ui_mywidget.h"
#include<QDebug>
#define cout qDebug() << "[" << __FILE__ << ":" << __LINE__ << "]"
MyWidget::MyWidget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::MyWidget)
{
ui->setupUi(this);
//动态分配空间,不能指定父对象
myT = new MyThread;
//创建子线程
thread = new QThread(this);
//把自定义线程加入到子线程中
myT->moveToThread(thread);
connect(myT,&MyThread::mySignal,this,&MyWidget::dealSignal);
cout<<"主线程号:"<<QThread::currentThread();
connect(this,&MyWidget::startThread,myT,&MyThread::myTimeOut);
connect(this,&MyWidget::destroyed,this,&MyWidget::dealClose);
}
MyWidget::~MyWidget()
{
delete ui;
}
void MyWidget::dealClose(){
cout<<"close1";//不知道为什么不走。。
on_btnStop_clicked();
delete myT;
}
void MyWidget::dealSignal(){
static int i = 0;
i++;
ui->lcdNumber->display(i);
}
void MyWidget::closeEvent(QCloseEvent *){
cout<<"close2";
on_btnStop_clicked();
delete myT;
}
void MyWidget::on_btnStart_clicked()
{
if(thread->isRunning()==true){
return;
}
//启动线程,但是没有启动线程处理函数
thread->start();
myT->setFlag(false);
//不能直接调用线程函数,
//直接调用,导致:线程处理函数和主线程是同一个线程。
//myT->myTimeOut();
//只能通过 signal-slot 方式调用
emit startThread();
}
void MyWidget::on_btnStop_clicked()
{
if(thread->isRunning()==false){
return;
}
myT->setFlag(true);
thread->quit();
thread->wait();
}
mythread
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QObject>
class MyThread : public QObject
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = nullptr);
//线程处理函数
void myTimeOut();
void setFlag(bool flag = true);
signals:
void mySignal();
private:
bool isStop;
};
#endif // MYTHREAD_H
#include "mythread.h"
#include <QThread>
#include<QDebug>
#define cout qDebug() << "[" << __FILE__ << ":" << __LINE__ << "]"
MyThread::MyThread(QObject *parent)
: QObject{parent}
{
isStop = false;
}
void MyThread::myTimeOut(){
while(isStop == false){
QThread::sleep(1);
emit mySignal();
cout<<"子线程号:"<<QThread::currentThread();
if(isStop)
{
break;
}
}
}
void MyThread::setFlag(bool flag){
isStop = flag;
}
线程画图
widget
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include<mythread.h>
#include<QThread>
#include<QImage>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
//重写绘图事件
void paintEvent(QPaintEvent *);
void getImage(QImage);//槽函数
void dealClose();
protected:
//void closeEvent(QCloseEvent *);
private:
Ui::Widget *ui;
QImage image;
MyThread *myT;
QThread *thread;
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
#include<QPainter>
#include<QDebug>
#define cout qDebug() << "[" << __FILE__ << ":" << __LINE__ << "]"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
myT = new MyThread;
thread = new QThread(this);
myT->moveToThread(thread);
//启动子线程,但是并没有启动线程处理函数
thread->start();
//线程处理函数,必须通过signal-slot调用
connect(ui->pushButton,&QPushButton::pressed,myT,&MyThread::drawImage);
connect(myT,&MyThread::updateImage,this,&Widget::getImage);
connect(this,&Widget::destroyed,[=](){
cout<<"close1";
if(thread->isRunning()==false){
return;
}
thread->quit();
thread->wait();
delete myT;
});
//connect(this,&Widget::destroyed,this,&Widget::dealClose);//只有这种方式不行。
}
Widget::~Widget()
{
delete ui;
}
void Widget::getImage(QImage temp){
image = temp;
update();
}
void Widget::paintEvent(QPaintEvent *e){
QPainter p(this);
p.drawImage(50,50,image);
}
/*
void Widget::closeEvent(QCloseEvent *){
cout<<"close3:";
if(thread->isRunning()==false){
return;
}
thread->quit();
thread->wait();
delete myT;
}
*/
void Widget::dealClose(){
cout<<"close2";
if(thread->isRunning()==false){
return;
}
thread->quit();
thread->wait();
delete myT;
}
mythread
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QObject>
#include<QImage>
class MyThread : public QObject
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = nullptr);
//线程处理函数
void drawImage();
signals:
void updateImage(QImage temp);
};
#endif // MYTHREAD_H
#include "mythread.h"
#include<QPainter>
#include<QPen>
#include<QBrush>
#include<cstdlib>
MyThread::MyThread(QObject *parent)
: QObject{parent}
{
}
void MyThread::drawImage(){
//定义QImage绘图设备
QImage image(500,500,QImage::Format_ARGB32);
//定义画家,指定绘图设备
QPainter p(&image);
//定义画笔对象
QPen pen;
pen.setWidth(5);
p.setPen(pen);
QBrush brush;
brush.setStyle(Qt::SolidPattern);
brush.setColor(Qt::red);
p.setBrush(brush);
//定义5个点
QPoint a[]{
QPoint(rand()%500,rand()%500),
QPoint(rand()%500,rand()%500),
QPoint(rand()%500,rand()%500),
QPoint(rand()%500,rand()%500),
QPoint(rand()%500,rand()%500)
};
p.drawPolygon(a,5);
//通过信号发送图片
emit updateImage(image);
}
数据库
MySQL需要输入账号密码,还需要连接的驱动文件。
SQLite比较简单,本地新建个后缀db的文件即可。
QT += sql
#include "widget.h"
#include "ui_widget.h"
#include<QSqlDatabase>
#include <QMessageBox>
#include <QSqlError>
#include <QSqlQuery>
#include <QVariantList>
#include<QDebug>
#define cout qDebug() << "[" << __FILE__ << ":" << __LINE__ << "]"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//打印QT支持的数据库驱动
cout<<QSqlDatabase::drivers(); // out: QList("QSQLITE", "QODBC", "QPSQL")
//添加sqlite数据库
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
//设置数据库 SQLite
db.setDatabaseName("../info.db");
//连接数据库 MySql
/*
db.setHostName("127.0.0.1"); //数据库服务器IP
db.setUserName("root"); //数据库用户名
db.setPassword("123456"); //密码
db.setDatabaseName("info"); //使用哪个数据库
*/
//打开数据库
if( !db.open() ){
QMessageBox::warning(this,"error",db.lastError().text());
}
QSqlQuery query;
// == 创建 ==
query.exec("create table student(id int primary key, name verchar(255), age int, score int);");
query.prepare("insert into student(name, age, score) values(?, ?, ?)");
//给字段设置内容 list
QVariantList nameList;
nameList << "xiaoming" << "xiaolong" << "xiaojiang" ;
QVariantList ageList;
ageList << 11 << 22 << 33;
QVariantList scoreList;
scoreList << 59 << 69 << 79;
//给字段绑定相应的值 按顺序绑定
query.addBindValue(nameList);
query.addBindValue(ageList);
query.addBindValue(scoreList);
//执行预处理命令
query.execBatch();
// == 查询 ==
query.exec("select * from student");
//一行一行遍历
while(query.next()){
//取出当前行的内容
qDebug() << query.value(0).toInt()
<< query.value(1).toString()
<< query.value("age").toInt()
<< query.value("score").toInt();
}
}
Widget::~Widget()
{
delete ui;
}
可视化操作
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include<QSqlTableModel>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_btnAdd_clicked();
void on_btnConfirm_clicked();
void on_btnCancel_clicked();
void on_btnDelete_clicked();
void on_btnFind_clicked();
private:
Ui::Widget *ui;
QSqlTableModel *model;
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
#include<QSqlDatabase>
#include <QMessageBox>
#include <QSqlError>
#include<QSqlRecord>
#include<QDebug>
#define cout qDebug() << "[" << __FILE__ << ":" << __LINE__ << "]"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//打印QT支持的数据库驱动
cout<<QSqlDatabase::drivers(); // out: QList("QSQLITE", "QODBC", "QPSQL")
//添加sqlite数据库
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
//设置数据库 SQLite
db.setDatabaseName("../info.db");
//打开数据库
if( !db.open() ){
QMessageBox::warning(this,"error",db.lastError().text());
}
//设置模型
model = new QSqlTableModel(this);
model->setTable("student");
//把model放在view
ui->tableView->setModel(model);
//显示model里的数据
model->select();
//设置 头部 显示
model->setHeaderData(0,Qt::Horizontal,"学号");
//设置model的编辑模式 手动提交修改
model->setEditStrategy(QSqlTableModel::OnManualSubmit);
//设置view中的数据库不允许修改
//ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_btnAdd_clicked()
{
//添加空记录
QSqlRecord record = model->record();//获取空记录
//获取行号
int row = model->rowCount();
model->insertRecord(row,record);
}
void Widget::on_btnConfirm_clicked()
{
model->submitAll();//提交动作
}
void Widget::on_btnCancel_clicked()
{
model->revertAll();//取消所有动作
model->submitAll();//提交动作
}
void Widget::on_btnDelete_clicked()
{
//获取选中的模型
QItemSelectionModel *sModel = ui->tableView->selectionModel();
//取出模型中的索引
QModelIndexList list = sModel->selectedRows();
//删除所有选中的行
for(int i=0; i<list.size();i++){
model->removeRow(list.at(i).row());
}
}
void Widget::on_btnFind_clicked()
{
QString name = ui->lineEdit->text();
QString str = QString("name = '%1'").arg(name);
model->setFilter(str);
model->select();
}
通用代码
#include<QDebug>
#define cout qDebug() << "[" << __FILE__ << ":" << __LINE__ << "]"