关于qt5:症状词表转化GUI

因为须要构建西医症状同义词库,须要从根本西医书籍中收集西医症状的同义词。《西医症状学钻研》里蕴含较多同义词,能够用来收集。然而,一个个输出太慢,能够利用OCR提取文字后,再依据文本格式特点将同义词主动提出进去。于是构建一个简略的gui程序,左侧输出原始文本,右侧输入提取的同义词文本。 1、创立新我的项目GUI_Tongyici 2、装置pyqt5D:\mypython\GUI_Tongyici\venv\Scripts>activate(venv) D:\mypython\GUI_Tongyici\venv\Scripts>pip install pyqt5(venv) D:\mypython\GUI_Tongyici\venv\Scripts>pip install pyqt5-tools(venv) D:\mypython\GUI_Tongyici\venv\Scripts>pip install pyqt5designer因为之前在Pycharm上配置过QtDesigner,所以此配置能够省略,如果没配置过,能够参考文章:https://blog.csdn.net/yuanchenglei/article/details/124936528 3、设计qt界面在我的项目上点击鼠标右键,找到第2步中配置好的PyQt5的QtDesigner,就会运行QtDesigner,就能够开始拖拽设计了。然而,因为很久没应用gui编程,呈现了一个小问题:拖拽过去的控件不会随着窗口大小变动主动调整!在代码外面设置最大化,在代码外面增加布局,居然都没有解决这个问题。于是在网上所搜了一下,发现要在QtDesigner设计中进行布局设置,而且布局不要之间拖布局进来,而是要在控件上点击右键增加布局。在右侧的对象查看器外面,如果以后的控件有那个红色禁止的符号,阐明以后没有增加布局。如下:增加布局须要留神:不要从左侧拖拽一个布局过去,而是在以后的控件上右键后抉择布局!最终,终于失去了能够随主窗口主动调整的布局和子空间了。 4、增加事件给转换pushbutton增加一个信号槽。 #增加信号槽 # self.pushButton.clicked.connect(self.plainTextEdit_2.close) self.pushButton.clicked.connect(self.convert)convert是一个自定义的事件处理函数,然而, 增加的自定义信号槽后,点击“转换”按钮基本没有响应。而应用正文中的零碎定义函数则没有问题。查找了很久,齐全没有没发现任何端倪。记得上一次如同也遇到了相似问题,把那个代码再看了一遍,用上次的代码,如同就有响应,区别就在main函数的调用形式上:上面这段是点击“转换”能响应的代码: if __name__ == '__main__': app = QApplication(sys.argv) myw = QMainWindow() # myWin = Ui_MainWindow().setupUi(myw) myWin = Ui_MainWindow() myWin.setupUi(myw) myw.show() sys.exit(app.exec())上面这个是点击“转换”按钮没有响应的代码 if __name__ == '__main__': app = QApplication(sys.argv) myw = QMainWindow() myWin = Ui_MainWindow().setupUi(myw) myw.show() sys.exit(app.exec())两者的区别在于正文的那一行!是不是第一种调用形式,使得Ui_MainWindow()对象存在的生命周期与正文中调用的生命周期不一样,而导致的呢? 5、转换函数

September 23, 2023 · 1 min · jiezi

关于qt5:Qt学习笔记基于Qtopencv的视频播放器

1、开发环境Qt:Qt5.14opencv:4.5.5 2、成果展现 能够实现播放、暂停、快进、后退、从新播放、进行、拖动进度条等性能; 3、代码性能解析3.1 opencv库加载因为应用了opencv的VideoCapture来加载视频,这里须要增加opencv的库,右键我的项目工程增加内部库,填入opencv的库和头文件门路,或者间接在皮肉文件下增加库的文件门路。 win32:CONFIG(release, debug|release): LIBS += -LD:/opencv/build/x64/vc15/lib/ -lopencv_world455else:win32:CONFIG(debug, debug|release): LIBS += -LD:/opencv/build/x64/vc15/lib/ -lopencv_world455dINCLUDEPATH += D:/opencv/build/includeDEPENDPATH += D:/opencv/build/include这里我的opencv门路在D盘对应门路下。 3.2 重写horizontalSlider点击事件这里须要点击进度条实现视频跳转到以后进度的性能,这里须要对horizontalSlider的点击事件函数进行重写。实现点击后获取点击处的进度值并更新进度条。 #include "newqslider.h"newqslider::newqslider(QWidget *parent) : QSlider(parent){}/****************************************************************** 函数名称:mousePressEvent(QMouseEvent *ev)* 性能形容:重写鼠标点击事件,实现进度条点击哪跳到哪* 参数阐明: 无* 返回值: 无******************************************************************/void newqslider::mousePressEvent(QMouseEvent *ev){ //先调用父类的鼠标点击处理事件,这样能够不影响拖动的状况 QSlider::mousePressEvent(ev); //获取鼠标的地位,这里并不能间接从ev中取值(因为如果是拖动的话,鼠标开始点击的地位没有意义了) double pos = ev->pos().x() / (double)width(); setValue(pos * (maximum() - minimum()) + minimum()); //发送自定义的鼠标单击信号 emit costomSliderClicked();}3.3 opencv采集线程videothread.h#include <QObject>#include <QThread>#include <opencv2/opencv.hpp>#include <iostream>#include <QDebug>#include <QDateTime>using namespace std;using namespace cv;class videothread : public QThread{ Q_OBJECTpublic: videothread(const char* filename); void run(); //开释视频采集对象 void releaseCap(); //获取视频总帧数 int getVideoAllFramecount(); //设置以后进度条 void setCurrentFrame(int value); bool getStop() const; //设置视频完结标识 void setStop(bool value); bool getIsrun() const; void setIsrun(bool value); //暂停 void pauseThread(); //持续 void resumeThread(); //进行 void stopThread();signals: //发送以后帧和 帧数 void sendFrame(int currentFrame,Mat frame);private: //视频对象 VideoCapture cap; Mat frame; //视频以后帧数 int currentFramecount; //总帧数 int allFramecount; //视频帧率 int fps; //录制视频帧 int videoWriterFrame; //线程完结标识位 bool stop; //视频暂停标识位 bool isrun;};采集线程中设置了暂停、持续播放、进行,并能够获取帧率和帧率数量; ...

August 23, 2023 · 2 min · jiezi

关于qt5:Qt学习笔记Qt下调用vlc库实现RTSP拉流播放和截图

1、介绍应用VLC-Qt库实现拉流播放器基本功能,包含拉流、播放、暂停、截图等性能。VLC-Qt库:一个对libVLC库根底上封装的开源库;推拉流服务器:ZLMediaKitde的MediaServer;推流工具:ffmpegVLC-Qt官网: VLC-Qt (tano.si)Github地址:VLC-Qt (github.com) 2、下载/配置VLC-Qt库进入VLC-Qt官网,依照本人的编译环境,下载对应的库和头文件,也能够去github仓库下载源码本人编译 我这里用的是MSVC64位,下载后库包含动静库、动态库和头文件 新建一个Qt的工程,增加第三方库,或间接在pro文件中配置以下: LIBS += -L$$PWD/libVLC/lib/ -lVLCQtCore -lVLCQtWidgetsINCLUDEPATH += $$PWD/libVLC/includeDEPENDPATH += $$PWD/libVLC/include3、设置视频播放控件因为在libvlc中须要本人获取控件的HWND句柄,并将播放绑定在控件句柄上,VLC-Qt间接封装了这个函数并间接赋值控件,不过控件须要降级到VlcWidgetVideo的类。咱们再ui上抉择一个widget的控件,右键降级 4、次要实现代码在main中要设置Vlc的Plugin,次要是依赖的插件 #include "widget.h"#include <QApplication>#include "VLCQtCore/Common.h"int main(int argc, char *argv[]){ QApplication a(argc, argv); VlcCommon::setPluginPath(a.applicationDirPath() + "/plugins"); Widget w; w.show(); return a.exec();}widget.h#ifndef WIDGET_H#define WIDGET_H#include <QWidget>#include "VLCQtCore/Common.h"#include "VLCQtCore/Instance.h"#include "VLCQtCore/Media.h"#include "VLCQtCore/MediaPlayer.h"QT_BEGIN_NAMESPACEnamespace Ui { class Widget; }QT_END_NAMESPACEclass Widget : public QWidget{ Q_OBJECTpublic: Widget(QWidget *parent = nullptr); ~Widget();private slots: void on_btn_startPlay_clicked(); void on_btn_pause_clicked(bool checked); void on_btn_stop_clicked(); void on_btn_snap_clicked();private: Ui::Widget *ui; VlcInstance * inst; VlcMediaPlayer *vlcPlayer; VlcMedia *vlcMedia;};#endif // WIDGET_Hwidget.cpp#pragma execution_character_set("utf-8")#include "widget.h"#include "ui_widget.h"Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget){ ui->setupUi(this); ui->btn_snap->setEnabled(false); inst = new VlcInstance(VlcCommon::args(), this); vlcPlayer = new VlcMediaPlayer(inst); vlcPlayer->setVideoWidget(ui->widget_video);}Widget::~Widget(){ delete ui;}void Widget::on_btn_startPlay_clicked(){ QString rtspUrl = ui->edt_rtspUrl->text(); if(!rtspUrl.isEmpty()) { vlcMedia = new VlcMedia(rtspUrl, inst); vlcPlayer->open(vlcMedia); ui->btn_snap->setEnabled(true); }}void Widget::on_btn_pause_clicked(bool checked){ if(checked) { ui->btn_pause->setText("持续"); } else { ui->btn_pause->setText("暂停"); } vlcPlayer->togglePause();}void Widget::on_btn_stop_clicked(){ vlcPlayer->stop(); ui->btn_snap->setEnabled(false);}void Widget::on_btn_snap_clicked(){ emit vlcPlayer->snapshotTaken("E:/123.jpg");}5、成果展现源码仓库) ...

May 29, 2023 · 1 min · jiezi

关于qt5:Qt学习笔记Qt使用mxDraw插件实现CAD二维图的显示和修改

介绍我的项目开发中可能呈现须要显示和加载dwg格局工程图或CAD绘图操作的性能时,须要调用CAD插件实现绘图操作或工程图展现。这里应用了MxDraw的CAD插件,其动静库须要在其官网上下载注册应用 插件的注册下载安装包后点击装置,装置插件后进入装置门路,而后点击RegMxDrawX.bat进行注册 注册实现后,零碎会自动识别插件 Qt调用插件在ui界面新增一个QAxWidget的控件,在控件右键,设置控件 选中控件属性为MxDrawX52 Control 设置完控件后,对控件进行布局治理 回到我的项目目录,在Qt的pro文件中增加插件库援用QT += axcontainer 设置实现后,运行程序,QAxWidget控件上就显示的是CAD的绘图插件了 Qt关上dwg文件显示应用以上设置,将dwg文件显示在QAxWidget控件上 代码 QFileDialog *fileDialog=new QFileDialog(); fileDialog->setFileMode(QFileDialog::ExistingFile); fileDialog->setNameFilter("dwg(*.dwg)"); QString openPath = QCoreApplication::applicationDirPath(); fileDialog->setDirectory(openPath); if(fileDialog->exec()==QDialog::Accepted) { QString srcFile=fileDialog->selectedFiles()[0]; QFileInfo fileinfo; fileinfo = QFileInfo(srcFile); qDebug()<<"srcFile"<<srcFile; ui->axWidget->dynamicCall("OpenDwgFile(const QString&)",srcFile); }

December 30, 2022 · 1 min · jiezi

关于qt5:QT-布局嵌套

QT布局一共有四种,罕用的三种,QHBoxLayout,QVBoxLayout,QGridLayout,在开发过程中,经常会碰到须要布局嵌套的状况,如果这样写 QVBoxLayout *m_layout = new QVBoxLayout(this);QHBoxLayout *m_hlayout1 = new QHBoxLayout(this);QHBoxLayout *m_hlayout2 = new QHBoxLayout(this);m_layout->addLayout(m_hlayout1);m_layout->addLayout(m_hlayout2);QT会报正告: 那么这个时候它会采纳哪个布局呢?最初增加的那个?不是的,它会都不采纳,应用零碎默认的布局。 那怎么实现嵌套布局呢?1.应用QWidget过渡 QVBoxLayout *m_layout = new QVBoxLayout(this);QWidget *m_widget1 = new QWidget(this);QHBoxLayout *m_hlayout1 = new QHBoxLayout(m_widget1);QWidget *m_widget2 = new QWidget(this);QHBoxLayout *m_hlayout2 = new QHBoxLayout(m_widget2);m_layout->addWidget(m_widget1);m_layout->addWidget(m_widget2);2.间接应用,结构里不传this进去(是否会内存透露?不会,addlayout会帮它治理好它的生命周期) QVBoxLayout *m_layout = new QVBoxLayout(this);QHBoxLayout *m_hlayout1 = new QHBoxLayout();QHBoxLayout *m_hlayout2 = new QHBoxLayout();m_layout->addLayout(m_hlayout1);m_layout->addLayout(m_hlayout2);测试代码与执行后果: //hlayout.h#ifndef HLAYOUT_H#define HLAYOUT_H#include <QHBoxLayout>class HLayout : public QHBoxLayout { public: HLayout(QWidget* parent = nullptr); ~HLayout();};#endif // HLAYOUT_H//hlayout.cpp#include "hlayout.h"#include <QDebug>HLayout::HLayout(QWidget* parent) : QHBoxLayout(parent) { qDebug() << "HLayout"; }HLayout::~HLayout() { qDebug() << "~HLayout"; }//vlayout.h#ifndef VLAYOUT_H#define VLAYOUT_H#include <QVBoxLayout>class VLayout : public QVBoxLayout { public: VLayout(QWidget* parent = nullptr); ~VLayout();};#endif // VLAYOUT_H//vlayout.cpp#include "vlayout.h"#include <QDebug>VLayout::VLayout(QWidget* parent) : QVBoxLayout(parent) { qDebug() << "VLayout"; }VLayout::~VLayout() { qDebug() << "~VLayout"; }//test.h#ifndef TEST_H#define TEST_H#include <QPushButton>class Test : public QPushButton { public: Test(QWidget* parent = nullptr); ~Test();};#endif // TEST_H//test.cpp#include "test.h"#include <QDebug>Test::Test(QWidget* parent) : QPushButton(parent) { qDebug() << "Test"; }Test::~Test() { qDebug() << "~Test"; }//mainwindow.h#ifndef MAINWINDOW_H#define MAINWINDOW_H#include <QMainWindow>#include "hlayout.h"#include "test.h"#include "vlayout.h"QT_BEGIN_NAMESPACEnamespace Ui { class MainWindow;}QT_END_NAMESPACEclass MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget* parent = nullptr); ~MainWindow(); private: Ui::MainWindow* ui; Test* m_test; Test* m_test1; VLayout* m_layout; HLayout* m_layout1; HLayout* m_layout2;};#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); m_test = new Test(this->centralWidget()); m_test->setText("test"); m_test1 = new Test(this->centralWidget()); m_test1->setText("test1"); m_layout = new VLayout(this->centralWidget()); m_layout1 = new HLayout; m_layout2 = new HLayout; m_layout1->addWidget(m_test); m_layout2->addWidget(m_test1); m_layout->addLayout(m_layout1); m_layout->addLayout(m_layout2);}MainWindow::~MainWindow() { delete ui; }//main.cpp#include "mainwindow.h"#include <QApplication>int main(int argc, char *argv[]){ QApplication a(argc, argv); MainWindow w; w.show(); return a.exec();} ...

October 8, 2022 · 2 min · jiezi

关于qt5:视觉实战案例QtHalcon实现区域生长算法坐标种子点灰度值种子点

1 算法介绍区域成长算法:将依照当时定义的成长准则讲一个像素或子区域逐渐聚合成一个残缺独立的区域的过程。对于图像上某个区域R,p为区域R上指定的一个像素点,称作种子点,依照规定的成长准则逐渐将与种子点z肯定邻域内合乎相似性判据的像素合并成一个种子群以备下一阶段的成长,这样一直的进行循环成长直到满足成长进行条件为止,从而实现了对感兴趣区域由一个种子点成长为一个独立连通区域的过程。 实现步骤1、在图像区域中选取一个像素点作为一个种子点(x,y)。2、依据成长规定,判断种子点四周八邻域的哪几个像素点能够作为下次成长的点,判断完后将该点存入生长点Vector,并将以后已用的种子点标记为已应用。3、依照规定判断下一个生长点。4、判断生长点vector容器中是否还有生长点,容器为空时完结。 Halcon中区域成长算子regiongrowing(Image:Regions : Row, Column, Tolerance, MinSize :)Row:被测试的区域的垂直距离Column:被测试的区域的程度间隔Tolerance:能忍耐的最大的灰度差距MinSize:最小的输入区域regiongrowing (Image111, Regions, 2, 2, 4, 100) 2 终点坐标种子点实现区域成长在区域成长的算法中,咱们须要输出一个已知的坐标点(x,y),以这个点作为终点,这里咱们不应用Halcon自带的区域成长算子,而是通过算法的步骤去实现这一性能。首先获取点击点的像素点灰度值,以这一点为起始点,向八畛域依照灰度差值去计算生长点。 HTuple Row,Col,Button; GetMbutton(m_hHalconID,&Row,&Col,&Button); if(Button == 1) { HObject ResultRegion;// HTuple posGray,GrayRows,GrayCols; GetGrayval(CurTestImg,Row, Col,&SelectGray); qDebug()<<"Gray"<<SelectGray.I(); int curGray = SelectGray.I(); ui->spb_gray->setValue(curGray); int index = ui->spb_growIndex->value(); int posY = Row.I(); int posX = Col.I(); QPoint pos(posX,posY); RegionGrowing(CurTestImg,ResultRegion,pos,index); FillUp(ResultRegion,&ResultRegion); UpdateImgWindow(); ui->PicShow->Region_ShowBuf.clear(); region_Info h_RegionInfo; h_RegionInfo.region = ResultRegion; h_RegionInfo.color = "#ff0000c0"; h_RegionInfo.size = 1; ui->PicShow->Region_ShowBuf.push_back(h_RegionInfo); ui->PicShow->updateShowInfoOnWindow(); }//区域成长算法void RegionGrowDlg::RegionGrowing(HObject img, HObject &region, QPoint pt,int th){ QPoint ptGrowing; //待生长点地位 HTuple nGrowLable = 0; //标记是否成长过 int nSrcValue = 0; //成长终点灰度值 int nCurValue = 0; //以后生长点灰度值// matDst = cv::Mat::zeros(src.size(), CV_8UC1); //创立一个空白区域,填充为彩色 //成长方向程序数据 int DIR[8][2] = { { -1, -1 }, { 0, -1 }, { 1, -1 }, { 1, 0 }, { 1, 1 }, { 0, 1 }, { -1, 1 }, { -1, 0 } }; std::vector<QPoint> vcGrowPt; //生长点栈 vcGrowPt.push_back(pt); //将生长点压入栈中 //首先设置区域为空 GenEmptyRegion(&region);// matDst.at<uchar>(pt.y, pt.x) = 255; //标记生长点 HTuple posGray; GetGrayval(img,pt.y(), pt.x(),&posGray); nSrcValue = posGray.I(); //记录生长点的灰度值 qDebug()<<"抉择点灰度"<<nSrcValue; while (!vcGrowPt.empty()) //成长栈不为空则成长 { pt = vcGrowPt.back(); //取出一个生长点 vcGrowPt.pop_back(); //别离对八个方向上的点进行成长 for (int i = 0; i < 8; ++i) { int ppx = (pt.x() + DIR[i][0]); int ppy = (pt.y() + DIR[i][1]); ptGrowing = QPoint(ppx,ppy); //查看是否是边缘点 if (ptGrowing.x() < 0 || ptGrowing.y() < 0 || ptGrowing.x() >(hv_Width - 1) || ptGrowing.y() > (hv_Height - 1)) continue; //判断该点是否在region内// int nGrowLable; TestRegionPoint(region,ptGrowing.y(), ptGrowing.x(),&nGrowLable);// HTuple curGray;// GetGrayval(img,ptGrowing.y, ptGrowing.x,&curGray);// nGrowLable = matDst.at<uchar>(ptGrowing.y, ptGrowing.x); //以后待生长点的灰度值 if (nGrowLable == 0) //如果标记点还没有被成长 { HTuple curGray; GetGrayval(img,ptGrowing.y(), ptGrowing.x(),&curGray); nCurValue = curGray.I();// nCurValue = src.at<uchar>(ptGrowing.y, ptGrowing.x);// if (abs(nSrcValue - nCurValue) < th) //在阈值范畴内则成长,这里抉择灰度在以后灰度值左右th个灰度内 if (nCurValue >nSrcValue || abs(nSrcValue - nCurValue) < th) { HObject PointRegion; GenRegionPoints(&PointRegion,ptGrowing.y(), ptGrowing.x()); Union2(PointRegion,region,&region);// matDst.at<uchar>(ptGrowing.y, ptGrowing.x) = 255; //标记为红色 vcGrowPt.push_back(ptGrowing); //将下一个生长点压入栈中 } } } }}从函数中能够看出,区域成长算法的输出是图像、坐标点、灰度断定值,输入为成长进去的Region区域。 ...

September 26, 2022 · 2 min · jiezi

关于qt5:Qt学习笔记Qt动态切换控件样式属性方法

1 介绍在编程过程中咱们个别应用setStyleSheet 函数来设置控件的款式属性,包含色彩、边框、透明度等属性,如果不同的控件和款式间接在代码中设置,会造成无奈对立治理的毛病,重复书写款式属性造成代码的冗余。解决的办法是将所有须要设置的款式属性都放入qss文件中,通过加载qss来实现不同控件不同状态下的款式变动。 2 实现过程如果咱们只设定某些控件的款式属性,能够把款式设置写到ui文件下的styleSheet下,其在ui下设置如下。 这里咱们设置按钮控件的款式属性,设置按钮默认是蓝色,鼠标停留在下面时按钮变为绿色,鼠标点击色彩为黄色,按钮选中色彩为红色。 QPushButton{ color: white; background-color: #27a9e3; border-width: 0px; border-radius: 3px;}QPushButton:hover{ color: white; background-color: #66c011; border-width: 0px; border-radius: 3px;}QPushButton:pressed{ color: white; background-color: yellow; border-width: 0px; border-radius: 3px;}QPushButton[pagematches=true]{ color: white; background-color: red; border-width: 0px; border-radius: 3px;}这里次要应用到的函数为setProperty()设置款式,polish()利用新的款式。 mainwindow.h#ifndef MAINWINDOW_H#define MAINWINDOW_H#include <QMainWindow>namespace Ui {class MainWindow;}class MainWindow : public QMainWindow{ Q_OBJECTpublic: explicit MainWindow(QWidget *parent = 0); ~MainWindow();private slots: void on_tabWidget_currentChanged(int index); void on_button1_clicked(); void on_button2_clicked(); void on_button3_clicked();private: Ui::MainWindow *ui;};#endif // MAINWINDOW_Hmainwindow.cpp#include "mainwindow.h"#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow){ ui->setupUi(this); ui->button1->setProperty("pagematches", true); ui->tabWidget->setCurrentIndex(0);}MainWindow::~MainWindow(){ delete ui;}void MainWindow::on_tabWidget_currentChanged(int index){ //分明所有按钮的选中款式 ui->button1->setProperty("pagematches", false); ui->button2->setProperty("pagematches", false); ui->button3->setProperty("pagematches", false); // 设置tab对应的按钮选中款式 if (index == 0) ui->button1->setProperty("pagematches", true); else if (index == 1) ui->button2->setProperty("pagematches", true); else ui->button3->setProperty("pagematches", true); // 每个按钮利用最新的款式设置 ui->button1->style()->polish(ui->button1); ui->button2->style()->polish(ui->button2); ui->button3->style()->polish(ui->button3);}void MainWindow::on_button1_clicked(){ ui->tabWidget->setCurrentWidget(ui->tab1);}void MainWindow::on_button2_clicked(){ ui->tabWidget->setCurrentWidget(ui->tab2);}void MainWindow::on_button3_clicked(){ ui->tabWidget->setCurrentWidget(ui->tab3);}3 成果展现本我的项目源码仓库 ...

September 24, 2022 · 1 min · jiezi

关于qt5:QT-如何隐藏掉QComboBox右侧的按钮

QT的QComboBox的款式布局如下图所示: 如果想暗藏掉左边的下拉框,怎么做呢? 很简略,想法必定是宽度设为0不就搞定了~ QComboBox::drop-down{ width:0px;}然而却没失效,这破玩意还在 怎么解决呢?给QComboBox增加属性 QComboBox { padding-right: 0px;}

September 18, 2022 · 1 min · jiezi

关于qt5:Qt学习笔记Qt程序加密实现软件运行次数和硬件信息绑定

前言程序员为了避免本人的成绩被白嫖,或者公布的软件在公司层面上要做一些防剽窃解决,这时就须要在软件层面上加锁、加密等操作。1、单机终端软件这类软件个别在未联网的状况下应用,所以不能通过网络去断定是否失去受权,个别采纳绑定硬件信息来对软件进行加密,这样软件与设施绑定就无奈进行随便应用。2、近程受权监控终端软件在启动后就会跟服务器通信来查看以后设施是否曾经失去受权,可实现近程锁定程序,设置程序的应用工夫和应用次数。以上两种办法都是最根底的软件加密办法,依据加密的算法的复杂度其破解的难度也不同,不过作为一般的一种加密办法曾经够用了,市面上有比拟成熟的加密加壳的软件,其平安水平要远高于软件加密的办法,下次抽时间介绍一下软件VMProtect的加、解密过程。 1、思路剖析单机软件想要每次启动前去验证是否有受权,须要从软件的配置中获取受权的验证信息,这里以软件的应用次数来举例,咱们须要把软件的可应用次数写入配置文件ini或数据库中。每次在软件重新启动时,咱们依据配置文件中信息来判断软件残余的应用次数。这里设定软件的残余应用次数为2次,不过这里有一个很显著的毛病,就是明文写到配置文件里,就能够本人批改,而后就失去了加密的属性,这里就须要对这个信息进行加密后再写入。这里应用Qt自带的base64对字符串进行加密。 2、实现函数//加密QString Widget::Encode(QString row){ QByteArray byteArray = row.toUtf8(); byteArray = byteArray.toBase64(); return byteArray;}//解密QString Widget::Decode(QString passwd){ QByteArray byteArray = passwd.toUtf8(); byteArray = QByteArray::fromBase64(byteArray); return byteArray;}//从配置文件获取信息QString Widget::getInfoFromIni(QString str){ QString info; QFile file(str); if(!file.exists()) { //如果文件不存在 QString times_str = "RemainTime:"+time; WriteInfo2Ini(str, times_str); } file.open(QFile::ReadWrite | QFile::Text); info = file.readAll(); //读取信息 file.close(); return info;}//将信息写入到配置文件void Widget::WriteInfo2Ini(QString str, QString info_text){ QFile file(str); file.open(QFile::ReadWrite | QFile::Text | QFile::Truncate); file.write(Encode(info_text).toUtf8()); //写入信息 file.close();}这种办法有一种弊病,就是如果从新笼罩配置文件能够跳出限度,比方这里如果事先拷贝一份ini文件,当软件次数为0后,从新拷贝原始ini文件后又取得初始的软件应用次数。如果思考不应用ini文件来记录受权信息,而是应用注册表来记录受权信息,这样软件使用者就不容易去发现受权信息的地位 void Widget::WriteInfo2Registry(QString str){ //写入注册表 QSettings settings("HKEY_CURRENT_USER\\Software\\Code_Encryption\\Settings",QSettings::NativeFormat); settings.setValue("remain_times",Encode(str).toUtf8());}QString Widget::getInfoFromRegistry(){ QString info; //通过写入注册表来判断 QSettings settings("HKEY_CURRENT_USER\\Software\\Code_Encryption\\Settings",QSettings::NativeFormat); info = settings.value("remain_times").toString(); return info;}3、示例代码widget.cpp#pragma execution_character_set("utf-8")#include "widget.h"#include "ui_widget.h"Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget){ ui->setupUi(this); QString str = getCpuId(); qDebug()<<"cpu id is"<<str;// QString times_str = "RemainTime:"+time;// WriteInfo2Registry(times_str); Judge_Authorize_times(1);}Widget::~Widget(){ delete ui;}QString Widget::getWMIC(const QString &cmd){ //获取cpu名称:wmic cpu get Name //获取cpu外围数:wmic cpu get NumberOfCores //获取cpu线程数:wmic cpu get NumberOfLogicalProcessors //查问cpu序列号:wmic cpu get processorid //查问主板序列号:wmic baseboard get serialnumber //查问BIOS序列号:wmic bios get serialnumber //查看硬盘:wmic diskdrive get serialnumber QProcess p; p.start(cmd); p.waitForFinished(); QString result = QString::fromLocal8Bit(p.readAllStandardOutput()); QStringList list = cmd.split(" "); result = result.remove(list.last(), Qt::CaseInsensitive); result = result.replace("\r", ""); result = result.replace("\n", ""); result = result.simplified(); return result;}QString Widget::getCpuId() //获取CPU序列号{ return getWMIC("wmic cpu get processorid");}QString Widget::getDiskNum() //获取硬盘序列号{ return getWMIC("wmic diskdrive where index=0 get serialnumber");}QString Widget::Encode(QString row){ QByteArray byteArray = row.toUtf8(); byteArray = byteArray.toBase64(); return byteArray;}QString Widget::Decode(QString passwd){ QByteArray byteArray = passwd.toUtf8(); byteArray = QByteArray::fromBase64(byteArray); return byteArray;}QString Widget::getInfoFromIni(QString str){ QString info; QFile file(str); if(!file.exists()) { //如果文件不存在 QString times_str = "RemainTime:"+time; WriteInfo2Ini(str, times_str); } file.open(QFile::ReadWrite | QFile::Text); info = file.readAll(); //读取信息 file.close(); return info;}void Widget::WriteInfo2Ini(QString str, QString info_text){ QFile file(str); file.open(QFile::ReadWrite | QFile::Text | QFile::Truncate); file.write(Encode(info_text).toUtf8()); //写入信息 file.close();}void Widget::WriteInfo2Registry(QString str){ //写入注册表 QSettings settings("HKEY_CURRENT_USER\\Software\\Code_Encryption\\Settings",QSettings::NativeFormat); settings.setValue("remain_times",Encode(str).toUtf8());}QString Widget::getInfoFromRegistry(){ QString info; //通过写入注册表来判断 QSettings settings("HKEY_CURRENT_USER\\Software\\Code_Encryption\\Settings",QSettings::NativeFormat); info = settings.value("remain_times").toString(); return info;}void Widget::Judge_Authorize_times(int type){ QString times_info; if(type == 0) { //通过ini配置文件进行判断 times_info = getInfoFromIni("System.ini"); } else { //通过写入注册表来判断 times_info = getInfoFromRegistry(); } if(times_info.isEmpty()) { QMessageBox::about(this,"提醒","受权信息为空,请查看!"); exit(0); } else { QString info = Decode(times_info); //解码 if(info.contains(':')) { //信息正确 QStringList list = info.split(':'); if(list.length()>=1) { if(list[1].toInt() <= 0) { //程序残余应用次数有余 QMessageBox::about(this,"提醒","请注册后再应用!"); exit(0); //程序退出 }else { //程序还有残余应用次数 QString time_remain = QString::number(list[1].toInt()-1); //程序残余应用次数减1 QString str = "RemainTime:"+time_remain; if(type == 0) WriteInfo2Ini("System.ini", str); else { //写入注册表 WriteInfo2Registry(str); } QMessageBox::about(this,"提醒","程序残余应用次数:"+time_remain+"次"); } } } }}widget.h#ifndef WIDGET_H#define WIDGET_H#include <QWidget>#include <QFile>#include <QMessageBox>#include <QProcess>#include <QDebug>#include <QSettings>namespace Ui {class Widget;}class Widget : public QWidget{ Q_OBJECTpublic: explicit Widget(QWidget *parent = 0); ~Widget();private: Ui::Widget *ui; QString getWMIC(const QString &cmd); QString getCpuId(); QString getDiskNum(); //加密 QString Encode(QString row); //解密 QString Decode(QString passwd); //判断受权信息 0:应用ini办法判断;1:应用注册表办法判断 void Judge_Authorize_times(int type); //从ini获取受权信息 QString getInfoFromIni(QString str); //写入受权信息到ini void WriteInfo2Ini(QString str, QString info_text); //从注册表获取受权信息 QString getInfoFromRegistry(); //写入受权信息到注册表 void WriteInfo2Registry(QString str); //受权程序应用次数为2次 QString time = "2";};#endif // WIDGET_H4、成果展现源码放到gitee仓库:Code_Encryption源码 ...

August 3, 2022 · 2 min · jiezi

关于qt5:Qt学习笔记QLabel实现圆形警示灯显示方法

1、应用Qt的design加载图像ico应用圆形警示灯ico图像填充QLabel控件,在design界面中选中label控件,在pixmap的属性下抉择不同的图片来填充。这种填充办法有一个毛病,就是图像没有进行缩放,这样label控件的大小就会导致无奈齐全显示图像,这里个别依照图像的宽高来设定label尺寸属性。这里程度和垂直策略都抉择Maximum,而后把minimumSize和MaximumSize都设置成图像大小。 2、应用setStyleSheet()函数来批改QLabelsetStyleSheet()函数能够用来批改控件的显示qss,能够间接调用该函数将Label控件设定成警示灯的显示模式。 min-width: 40px; //最小宽度 40pxmin-height: 40px; //最小高度 40pxmax-width: 40px; //最大宽度 40px max-height: 40px; //最大高度 40pxborder-radius: 20px; //边框是圆角,半径20pxborder:1px solid black; //边框1px,边框彩色background: red; //背景是红色这里设定宽度高度和圆角,将Label显示成圆形状态。 const QString m_red_SheetStyle = "min-width: 40px; min-height: 40px;max-width:40px; max-height: 40px;border-radius: 20px; background:red"; const QString m_green_SheetStyle = "min-width: 40px; min-height: 40px;max-width:40px; max-height: 40px;border-radius: 20px; ;background:green"; const QString m_gray_SheetStyle = "min-width: 40px; min-height: 40px;max-width:40px; max-height: 40px;border-radius: 20px; border:1px solid black;background:grey"; const QString m_yellow_SheetStyle = "min-width: 40px; min-height: 40px;max-width:40px; max-height: 40px;border-radius: 20px; border:1px solid black;background:yellow"; ui->lab_LED_R->setStyleSheet(m_red_SheetStyle);// 红色圆形警示灯 ui->lab_LED_G->setStyleSheet(m_green_SheetStyle);//绿色圆形警示灯 ui->lab_LED_B->setStyleSheet(m_yellow_SheetStyle);//黄色圆形警示灯 ui->lab_LED_GR->setStyleSheet(m_gray_SheetStyle);//灰色圆形警示灯这里只介绍了简略的setStyleSheet()函数利用,包含一些过渡,通明等成果都能够应用setStyleSheet()函数来进行设置,这里就不开展了。 ...

July 12, 2022 · 1 min · jiezi

关于qt5:Qt学习笔记Qt线程间数据通讯及数据共享

1、背景介绍在应用QT做我的项目开发过程中,常常会用到多线程,比方图像采集一个线程,图像处理一个线程、数据通讯一个线程。这些不同的线程中会呈现数据共享的需要,Qt线程间共享数据次要有三种形式: 1.应用共享内存;即两个线程都可能共享的变量(全局变量),这样两个线程都可能拜访和批改变量,从而达到祝贺目标;2.应用信号槽机制,将数据从一个线程传递到另外一个线程3.共享类指针来进行拜访不同类的变量和函数;第三种是我本人罕用的办法,在上面我总结记录一下。 2、 办法介绍第一种办法,应用全局变量或全局函数,在其余类或线程中调用,这是各种编程语言中都通用的办法,但全局变量长时间占用内存,影响程序空间使用率,且全局变量批改影响整个程序,程序的安全性无奈保障,个别尽量少用全局变量或函数,这种办法不开展介绍了。 2.1 信号槽进行数据通讯信号槽性能是QT特有的性能,应用信号槽须要留神以下几个事项: 只有QObject类及其派生的类能力应用信号和槽的机制在线程间应用信号槽进行通信时,槽参数必须应用元数据类型的参数;如果应用自定义的数据类型,须要在connect之前将其注册(qRegisterMetaType)为元数据类型;线程间用信号槽传递参数的话,要加const,因为const文字常量存在常量区中,生命周期和程序一样长。这样能够防止slot调用的时候参数的运行期已过造成援用有效;这里我用一个balser相机线程采图应用信号槽发到UI线程显示的Demo来展现一下线程间通过信号槽的数据通讯。 /*图像采集线程头文件*//*GrabThread.h*/#pragma execution_character_set("utf-8")#ifndef _GRABTHREAD_H#define _GRABTHREAD_H#include <Qtwidgets>#include <QtCore>#include <QtGui>#include <pylon/PylonIncludes.h>#include <QThread>#include "opencv2/opencv.hpp"using namespace Pylon;class GrabThread : public QThread{ Q_OBJECTpublic: GrabThread(); ~GrabThread(); void run(); void init(CInstantCamera &m_camera); bool isInit(); void stop(); void save(bool); void grab(int g =1); cv::Mat Result2Mat(CGrabResultPtr &ptrGrabResult); CInstantCamera *m_camera; CGrabResultPtr ptrGrabResult; //Basler 获取后果指针 CImageFormatConverter m_formatConverter;//Basler 图片格式转换类 CPylonImage pylonImage; //Basler 图像格式 QImage m_image; //Qt图片格式 QPixmap m_pix; String_t m_prefix; bool m_stop; bool m_init; bool m_save; int m_grab; //获取图像策略 0示意间断获取,1示意获取单帧 int m_num_one; int m_num_continue; signals: //发给UI线程的信号 void ThreadPic(cv::Mat outputPix);};#endif// GRABTHREAD_HGrabThread.cpp#include "GrabThread.h"GrabThread::GrabThread(){ m_formatConverter.OutputPixelFormat = PixelType_Mono8; m_stop = false; m_init = false; m_save = false; m_grab = 0; m_num_continue = 0; m_num_one = 0;}GrabThread::~GrabThread(){}void GrabThread::run(){ try { m_camera->StartGrabbing(GrabStrategy_LatestImageOnly); while (m_camera->IsGrabbing() && !m_stop) { m_camera->RetrieveResult(5000000, ptrGrabResult); if (ptrGrabResult->GrabSucceeded()) { //格局转换 cv::Mat MatImg = Result2Mat(ptrGrabResult); // qDebug() << "转换胜利" << endl; //发射信号 emit ThreadPic(MatImg); } } m_stop = false; m_camera->StopGrabbing(); } catch (const GenericException &e) { // Error handling. qDebug() << "An exception occurred." << endl << e.GetDescription() << endl; } return;}void GrabThread::init(CInstantCamera &input_camera){ m_camera = &input_camera; m_init = true;}bool GrabThread::isInit(){ return m_init;}void GrabThread::stop(){ m_stop = true; this->wait();}void GrabThread::save(bool s){ m_save = s;}void GrabThread::grab(int g){ m_grab = g;}cv::Mat GrabThread::Result2Mat(CGrabResultPtr &ptrGrabResult){ ////格局转换 m_formatConverter.Convert(pylonImage, ptrGrabResult); uchar * din = (uchar *)(pylonImage.GetBuffer()); //数据指针 cv::Mat cvImage = cv::Mat(ptrGrabResult->GetHeight(),ptrGrabResult->GetWidth(),CV_8UC1,din).clone(); return cvImage;}在采集线程中收回的信号,在UI线程就要有对应的槽函数。/* imgShowWidget.h */#ifndef IMGSHOWWIDGET_H#define IMGSHOWWIDGET_H#include <QWidget>#include "opencv2/opencv.hpp"namespace Ui {class ImgShowWidget;}class ImgShowWidget : public QWidget{ Q_OBJECTpublic: explicit ImgShowWidget(QWidget *parent = 0); ~ImgShowWidget();private: Ui::ImgShowWidget *ui; QImage cvMat2QImage(const cv::Mat& mat); cv::Mat QImage2Mat(QImage image);private slots: //显示图像的槽函数 void Thread_Img(cv::Mat img);};#endif // IMGSHOWWIDGET_HImgShowWidget.cpp#include "imgshowwidget.h"#include "ui_imgshowwidget.h"#include <QDebug>#include <QElapsedTimer>using namespace cv;ImgShowWidget::ImgShowWidget(QWidget *parent) : QWidget(parent), ui(new Ui::ImgShowWidget){ ui->setupUi(this); qRegisterMetaType<Mat>("Mat");}ImgShowWidget::~ImgShowWidget(){ delete ui;}void ImgShowWidget::Thread_Img(cv::Mat img){ QImage Qimg; if(isWork) { QElapsedTimer ElapsedTimer; ElapsedTimer.start(); Mat ResultImg = m_ProcessObj->DetectProcess(img); qDebug()<<"耗时"<<ElapsedTimer.elapsed()<<"毫秒"; Qimg = cvMat2QImage(ResultImg); } else { Qimg = cvMat2QImage(img); } QPixmap m_pix = QPixmap::fromImage(Qimg); m_pix = m_pix.scaled(ui->PicShow->size(), Qt::KeepAspectRatio); ui->PicShow->setPixmap(m_pix);}QImage ImgShowWidget::cvMat2QImage(const cv::Mat &mat){ switch ( mat.type() ) { // 8-bit 4 channel case CV_8UC4: { QImage image( (const uchar*)mat.data, mat.cols, mat.rows, static_cast<int>(mat.step), QImage::Format_RGB32 ); return image; } // 8-bit 3 channel case CV_8UC3: { QImage image( (const uchar*)mat.data, mat.cols, mat.rows, static_cast<int>(mat.step), QImage::Format_RGB888 ); return image.rgbSwapped(); } // 8-bit 1 channel case CV_8UC1: { static QVector<QRgb> sColorTable; // only create our color table once if ( sColorTable.isEmpty() ) { sColorTable.resize( 256 ); for ( int i = 0; i < 256; ++i ) { sColorTable[i] = qRgb( i, i, i ); } } QImage image( (const uchar*)mat.data, mat.cols, mat.rows, static_cast<int>(mat.step), QImage::Format_Indexed8 ); image.setColorTable( sColorTable ); return image; } default: qDebug("Image format is not supported: depth=%d and %d channels\n", mat.depth(), mat.channels()); qWarning() << "cvMatToQImage - cv::Mat image type not handled in switch:" << mat.type(); break; } return QImage();}这里就是第一种信号槽的办法,通过emit ThreadPic(MatImg)发送信号,在UI线程通过槽函数Thread_Img(cv::Mat img)来接管Mat类型的图像进行显示,这里Mat类型不是Qt的元数据,所以要应用qRegisterMetaType<Mat>("Mat")来进行注册。 ...

February 16, 2022 · 3 min · jiezi

关于qt5:Qt学习笔记Qt使用MFC编译生成dll库在无编程环境电脑出现无法加载dll的问题

1、 问题介绍在我的项目实际中,应用Qt调用了一个vs创立的dll库,在本机上编译和release后的exe能够加载对应的dll文件,将exe拷贝到有vs编程环境的电脑上也能够加载对应的dll文件,但在无编程环境的电脑上执行exe就会呈现无奈加载dll的bug。 2、 问题剖析刚碰到这个问题的时候,感觉可能是dll的依赖项的的确,或者是vc运行库的缺失,如是在新电脑上装置了VC运行库,并应用dependency walker查看了该dll的依赖项并进行补全,发现问题仍然存在,接下来思考的是dll自生生成的环境依赖问题,如是找到了该dll我的项目的生成环境,将dll生成的运行库设置为“多线程(/MT)”,再从新生成dll就解决新电脑无奈加载dll的bug。 3、 问题总结和思考这里重新学习一下MFC这种生成dll设定运行库的原理。 编译选项蕴含动态链接的lib阐明/MD_MT、_DLLMSVCRT.lib多线程、Release、DLL版本的运行时库/MDd_DEBUG、_MT、_DLLMSVCRTD.lib多线程、Debug、DLL版本的运行时库/MT_MTLIBCMT.lib多线程、Release版本的运行时库/MTd_DEBUG、_MTLIBCMTD.lib多线程、Debug版本的运行时库这里就要留神/MD和/MT的区别了 /MD示意运行时库不集成,个别生成的文件小,如果零碎有依赖库可无效缩小文件大小。/MT示意运行时库集成,生成文件大,自带了该dll的依赖库/MT和/MD抉择的要领 1 以下状况抉择/MT1)有些零碎可能没有程序所需版本的运行时库,程序必须把运行时库动态链接上;2)缩小模块对外界的依赖;2 以下状况抉择/MD1)程序就不须要动态链接运行时库,能够减小软件的大小;2)所有的模块都采纳/MD,应用的是同一个堆,不存在A堆申请,B堆开释的问题;3)用户机器可能短少咱们编译时应用的动静运行时库。(补充:如果咱们软件有多个DLL,采纳/MT体积减少太多,则能够思考/MD + 自带零碎运行时库)3 留神:如果软件有多个模块dll,必须抉择雷同的运行时库;

February 16, 2022 · 1 min · jiezi

关于qt5:Qt学习笔记QPushButton点击事件和长按事件使用功能

1、背景介绍在应用QPushButton中,个别都在UI界面间接右键增加槽函数进入代码,很少去剖析每个触发事件的性能,比方须要通过长按按钮来触发相应的操作,这里点击信号不能够达到预期的成果。 2、功能分析首先剖析QPushButton的点击信号,QPushButton有三个罕用的信号: pressed() —— 当鼠标在button上并点击左键的时候发射,最先执行;released()——当鼠标左键被开释的时候clicked() —— 当鼠标首先按下pressed,而后开释,最初执行;toggled() —— 按下之后状态发生变化,触发toggled;本来认为Pressed和clicked没有区别,深入研究才发现自己格局小了;首先,这三个信号都是从QAbstractButton继承来的,也就是对AbstractButton的所有子类都实用。按键长按事件的原理就是鼠标按下Delay工夫后会启动一个屡次触发的TimerEvent(定时器),由timeOut再次触发click槽。 3、实现代码 QPushButton *pBtnSub = new QPushButton(this); pBtnSub->setAutoRepeat(true); //启用长按 pBtnSub->setAutoRepeatDelay(400);//触发长按的工夫 pBtnSub->setAutoRepeatInterval(50);//长按时click信号距离 connect(pBtnSub,&QPushButton::clicked,[&]{ qDebug()<<"send";}); 测试源码:AutoRepeat_Test

January 6, 2022 · 1 min · jiezi

关于qt5:Qt学习笔记Release后的exe程序在新的电脑上出现找不到MSVCP140dll的错误

1、背景介绍咱们在打包程序的时候个别都会把相干依赖库整体打包,这样程序在新的电脑和环境下就不须要再去配置对应的环境,然而有时候新程序在一台新的电脑运行时会呈现“找不到MSVCP140.dll”这种谬误,其起因就是在新电脑的操作系统中短少一些不要的依赖库,须要找齐这些库放到新电脑的零碎中。所以须要装置对应的依赖库。 2、解决方案这里有两种解决方案,第一种是修复一下装置的VS软件。这种办法次要是针对装置有VS(VC)搞编程开发的小伙伴。 2.1 修复VS解决次要通过修复VS装置软件,来从新获取这些依赖库关上电脑的“控制面板”,找到“程序”,找到VS的装置软件,右键“更改”,对软件进行修复。下面的办法比拟适宜编程的小伙伴。然而如果一般宅男只想打机,不想那么麻烦的话,就举荐第二种办法; 2.2 间接装置依赖库在网上下载库安装程序,将依赖库重新安装一次,间接在百度云上下载链接:https://pan.baidu.com/s/1vdHY... 提取码:xx2u下载后间接下一步装置,装置胜利后再运行之前报错的的软件就会发现运行胜利了。

December 24, 2021 · 1 min · jiezi

关于qt5:QtMPlayer音乐播放器开发笔记二交叉编译MPlayer以及部署到开发板播放演示

前言 在ubuntu上arm穿插编译MPlayer播放器,并部署到开发板播放音乐。 Demo Mplayer MPlayer是一款开源多媒体播放器,以GNU通用公共许可证公布。此款软件可在各支流操作系统应用,例如Linux和其余类Unix零碎、Windows及Mac OS X零碎。 MPlayer基于命令行界面,在各操作系统也可抉择装置不同的图形界面。mplayer的另一个大的特色是宽泛的输出设备反对。它能够在X11、Xv、DGA、OpenGL、SVGAlib、fbdev、AAlib、DirectFB下工作,且能应用GGI和SDL和一些低级的硬件相干的驱动模式(比方Matrox、3Dfx和Radeon、Mach64、Permedia3)。MPlayer还反对通过硬件MPEG解码卡显示,如DVB 和DXR3与Hollywood+。 MPlayer的开发始于2000年。最后的作者是 Arpad Gereoffy。MPlayer最后的名字叫"MPlayer - The Movie Player for Linux",不过起初开发者们简称其为"MPlayer - The Movie Player",起因是MPlayer曾经不仅能够用于Linux而能够在所有平台上运行。 下载 最新源码下载地址: http://mplayerhq.hu/design7/news-archive.html QQ群:1047134658(点击“文件”搜寻“MPlayer”,群内与博文同步更新) Ubuntu穿插编译Mplayer步骤一:下载解压tar xvf MPlayer-1.4.tar.xz 步骤二:configurecd MPlayer-1.4/./configure \ --prefix=/home/yang/work/rootfs/mplayer \ --host-cc=gcc \ --cc=arm-linux-gnueabihf-9.1.0-gcc \ --yasm='' 步骤三:make,“error impossible constraint in asm”make -j4 此处,是因为平台的指令集问题,增加平台参数 ./configure \ --prefix=/home/yang/work/rootfs/mplayer \ --host-cc=gcc \ --cc=arm-linux-gnueabihf-9.1.0-gcc \ --yasm='' \ --target=arm-linux 步骤四:make,须要zlib库撑持,引入zlib库make zlib库的穿插编译请参照博文《zlib开发笔记(三):zlib库介绍、在ubuntu上进行arm平台穿插编译》 增加穿插编译的zlib库后,增加门路后重新配置: ./configure \ --prefix=/home/yang/work/rootfs/mplayer \ --host-cc=gcc \ --cc=arm-linux-gnueabihf-9.1.0-gcc \ --yasm='' \ --target=arm-linux \ --extra-cflags=-I/home/yang/work/rootfs/zlib-1.2.11/include \ --extra-ldflags=-L/home/yang/work/rootfs/zlib-1.2.11/lib 持续make,直至编译实现 ...

August 30, 2021 · 1 min · jiezi

关于qt5:案例分享Qt政务标签设计器标签排版软件定制与打印

需要 1.标签设计器; 2.具备文字排版性能; 3.反对六种排版格局; 4.排版后能够输入打印(demo中不蕴含); 5.排版后能够输入标签的指定协定文本FBD格局; 6.能够调整对应标签的一些地位,x,y,宽度,高度,横向间距,纵向间距; 7.反对排版后的标签预览; 8.标签排版文本谬误提醒; Demo v1.6.0 在这里插入图片形容 在这里插入图片形容 在这里插入图片形容 在这里插入图片形容 在这里插入图片形容 在这里插入图片形容 在这里插入图片形容 体验下载地址 CSDN(粉丝免积分下载):https://download.csdn.net/dow... QQ群:1047134658(点击“文件”搜寻“labelDesigner ”,群内与博文同步更新) 模块化 模块化设计构架: 在这里插入图片形容 外围源码头文件Widget.h ifndef WIDGET_Hdefine WIDGET_Hinclude <QTextCodec>include <QWidget>include <QAbstractButton>include <QFileDialog>include <QMessageBox>include "LabelWidget.h"namespace Ui {class Widget;} class Widget : public QWidget{ Q_OBJECTpublic: explicit Widget(QWidget *parent = 0);~Widget();protected: void initControls();void createLabelWidgets();void updateLabelWidgets();void updateScale();QStringList parseNames(QString content);protected slots: void slot_updateScale();void slot_buttonClicked(QAbstractButton *pAbstractButton);protected: void resizeEvent(QResizeEvent *event);private slots: void on_spinBox_x_valueChanged(int arg1);void on_spinBox_y_valueChanged(int arg1);void on_spinBox_xNumber_valueChanged(int arg1);void on_spinBox_yNumber_valueChanged(int arg1);void on_spinBox_labelWidth_valueChanged(int arg1);void on_spinBox_labelHeight_valueChanged(int arg1);void on_doubleSpinBox_scale_valueChanged(double arg1);void on_spinBox_labelVerticallSpace_valueChanged(int arg1);void on_spinBox_labelHorizalSpace_valueChanged(int arg1);void on_textEdit_names_textChanged();void on_pushButton_createLabel_clicked();void on_pushButton_export_clicked();private: ...

August 16, 2021 · 2 min · jiezi

关于qt5:Ubuntu1804实现Aarch64和arm32的交叉编译全步骤含Qt51210源码编译

Ubuntu18.04实现Aarch64和arm32的穿插编译全步骤(含Qt5.12.10源码编译)本文所应用的文件下载: 百度网盘: 链接:https://pan.baidu.com/s/1mnpFepFY-rOlwWd3QbYZiw 提取码:5566 下载穿插编译链接工具) 装置穿插编译器解压 sudo tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar -C /opt/sudo tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar -C /opt/解压实现后,配置环境变量 sudo vim ~/.bashrc增加编译器门路:门路为你解压后门路,我的门路为:/opt/ PATH=$PATH:/opt/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/binPATH=$PATH:/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin 配置失效 source ~/.bashrc验证是否装置胜利 aarch64-linux-gnu-gcc -varm-linux-gnueabihf-gcc -varm32如下为胜利。 aarch64如下为胜利 测试穿插编译器写一个简略的c程序,穿插编译后放到开发板下来运行看看 是否运行胜利 #include <stdio.h>int main(int argc, char **argv){ printf("Hello, you do it succeed!!!\n"); return 0;}先应用arm32编译 编译实现后,看到文件是32位的。 移植到arm32板子上,能够运行胜利。 aarch64编译 编译实现后,看到文件是arm 64位的。 移植到aarch64的板子上,能够运行胜利。 由此可见,两种穿插编译工具都装置胜利,能够应用。 编译Qt源码这里只是用aarch64编译器去编译qt源码 下载Qt源码 解压qt源码sudo tar xvf qt-everywhere-src-5.12.10.tar.xzcd qt-everywhere-src-5.12.10批改qmake配置文件首先复制一份文件 sudo cp -a linux-aarch64-gnu-g++/ aarch64-linux-gnu-g++/批改配置文件目录,前面都改成你穿插编译器装置的门路。”/opt/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/“ # modifications to g++.confQMAKE_CC = /opt/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc QMAKE_CXX = /opt/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-g++ QMAKE_LINK = /opt/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-g++ QMAKE_LINK_SHLIB = /opt/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-g++ # modifications to linux.confQMAKE_AR = /opt/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-ar cqsQMAKE_OBJCOPY = /opt/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-objcopyQMAKE_NM = /opt/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc-nm -PQMAKE_STRIP = /opt/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-stripload(qt_config) ...

June 13, 2021 · 8 min · jiezi

关于qt5:Qt开发技术图形视图框架二场景QGraphicsSceneQGraphicsItem与QGraphicsView详解

若该文为原创文章,转载请注明原文出处本文章博客地址:https://hpzwl.blog.csdn.net/article/details/117660217 各位读者,常识无穷而人力有穷,要么改需要,要么找专业人士,要么本人钻研 红瘦子(红模拟)的博文大全:开发技术汇合(蕴含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬联合等等)继续更新中…(点击传送门) Qt开发专栏:开发技术(点击传送门)上一篇:《Qt开发技术:图形视图框架(一)根本介绍》下一篇:敬请期待 前话 Qt的图形视图框架,最外围的三个类为:QGraphicsScene、QGraphicsItem与QGraphicsView。 QGraphicsScene形容 QGraphicsScene类提供了一个用于治理大量二维图形项的面。 该类用作QGraphicsItems的容器。它与QGraphicsView一起用于在二维面上可视化图形项,例如线条、矩形、文本,甚至自定义项。QGraphicsScene是图形视图框架的一部分。 QGraphicScene还提供了一些性能,能够让无效地确定我的项目的地位,以及确定在场景中任意区域内哪些项目可见。应用QGraphicsView小部件,能够可视化整个场景,或者放大并只查看场景的局部。 示例: QGraphicsScene *pScene = new QGraphicsScene();pScene->addText("Hello, world!");QGraphicsView *pView = new QGraphicsView(pScene, this); 请留神,QGraphicScene自身没有视觉外观;它只治理我的项目。须要创立一个QGraphicsView小部件来可视化场景(设置它的父类为可视窗口,如QWidget)。 要将我的项目增加到场景中,首先要结构一个QGraphicsScene对象。而后,有两个选项:要么通过调用addIitem()增加现有的QGraphicsItem对象(次要是自定义继承的QGraphicsItem),要么调用便当函数addEllipse()、addLine()、addPath()、addPixmap()、addPolygon()、addRect()或addText(),这些函数都返回指向新增加项的指针。应用这些函数增加的我的项目的尺寸是绝对于我的项目的坐标系的,并且我的项目地位在场景中初始化为(0,0)。 而后能够应用QGraphicsView可视化场景。当场景更改时(例如,当我的项目挪动或转换时),QGraphicScene会收回changed()信号。若要删除项,请调用RemoveItem()。 QGraphicScene应用索引算法来无效地治理我的项目的地位。默认状况下,应用BSP(二进制空间分区)树;该算法实用于大多数我的项目放弃动态(即不挪动)的大型场景。能够通过调用setItemIndexMethod()来抉择禁用此索引。无关可用索引算法的详细信息,请参阅ItemIndexMethod属性。 场景的边界矩形是通过调用setSceneRect()设置的。我的项目能够搁置在场景的任何地位,默认状况下,场景的大小是有限的。场景矩形仅用于外部记账,保护场景的项索引。如果场景rect未设置,QGraphicScene将应用itemsBoundingRect()返回的所有项的边界区域作为场景矩形。然而,itemsBoundingRect()是一个绝对耗时的函数,因为它通过收集场景中每个我的项目的地位信息来操作。因而,在大型场景上操作时,应始终设置场景矩形。 QGraphicScene最大的长处之一是它可能无效地确定我的项目的地位。即便现场有数百万个我的项目,items()函数也能够在几毫秒内确定我的项目的地位。items()有几个重载:一个在特定地位查找我的项目,一个在多边形或矩形内或与多边形或矩形相交的我的项目,等等。返回我的项目的列表按重叠程序排序,最下面的我的项目是列表中的第一个我的项目。为了不便起见,还有一个itemAt()函数在给定地位返回最下面的项。 QGraphicScene保护场景的抉择信息。要选择项,请调用setSelectionArea(),要革除以后抉择,请调用clearSelection()。调用selectedItems()以获取所有选定项的列表。 事件处理和流传 QGraphicsScene的另一个职责是从QGraphicsView流传事件。要将事件发送到场景,能够结构继承QEvent的事件,而后应用QApplication::SendEvent()发送它。event()负责将事件分派给各个我的项目。一些常见事件由不便的事件处理程序解决。例如,按键事件由keypressEvent()解决,鼠标按键事件由mousePressEvent()解决。 要害事件传递到焦点我的项目。要设置焦点项,能够调用setFocusItem(),传递承受焦点的项,或者项自身能够调用QGraphicsItem::setFocus()。调用focusItem()以获取以后焦点项。为了与小部件兼容,场景还保护本人的焦点信息。默认状况下,场景没有焦点,所有要害事件都将被抛弃。如果调用了setFocus(),或者场景中的某个我的项目取得焦点,则场景将主动取得焦点。如果场景有焦点,hasFocus()将返回true,并且要害事件将转发到焦点项(如果有的话)。如果场景失去焦点(即有人调用clearFocus()),而某个我的项目有焦点,则该场景将放弃其我的项目焦点信息,并且一旦场景复原焦点,它将确保最初一个焦点我的项目复原焦点。 对于鼠标悬停成果,QGraphicsScene会发送悬停事件。如果一个项承受悬停事件(请参见QGraphicsItem::acceptHoverEvents()),则当鼠标进入其区域时,它将收到一个QGaphicsSceneHoverCenter事件。当鼠标持续在我的项目区域内挪动时,QGraphicsScene将向其发送GraphicsSceneHoverMove事件。当鼠标来到我的项目区域时,我的项目将收到一个GraphicsSceneHoverLeave事件。 所有鼠标事件都将传递到以后鼠标抓取器项。如果一个我的项目承受鼠标事件(请参见QGraphicsItem::acceptedMouseButtons())并接管到鼠标按下,它将成为场景的鼠标抓取器。它放弃鼠标抓取器,直到在没有其余鼠标按钮被按下时收到鼠标开释为止。能够调用mouseGramberItem()来确定以后正在获取鼠标的项。 QGraphicsView QGraphicsView类提供一个窗口,用于显示QGraphicsScene的内容。 在QGraphicsView将可视内容滚动的视口中。几何项创立场景的步骤参考,QGraphicsScene的文档,QGraphicsView图形视图框架的一部分。可视化一个场景,通过建构QGraphicsView通过对象的地址,可看QGraphicsView的构造函数,或者也能够随后调用setScene()显示。在你调用show(),视窗将默认将滚动到视图核心并显示可见的所有我的项目。例如: QGraphicsScene *pScene = new QGraphicsScene();pScene->addText("Hello, world!");QGraphicsView *pView = new QGraphicsView(pScene, this); 能够应用滚动条或调用centerOn()显式滚动到场景中的任何地位。通过将点传递给centerOn(),QGraphicsView将滚动其视区以确保该点在视图中居中。提供了一个用于滚动到QGraphicsItem的重载,在这种状况下,QGraphicsView将看到该项的核心在视图中居中。如果只想确保某个区域是可见的(但不肯定是居中的),那么能够调用ensureVisible()。 QGraphicsView能够用来可视化整个场景,或者只显示其中的一部分。默认状况下,在首次显示视图时自动检测可视化区域(通过调用QGraphicsScene::itemsBoundingRect())。要本人设置可视化区域矩形,能够调用setScenRect()。这将适当调整滚动条的范畴。请留神,只管场景反对简直不受限制的大小,但滚动条的范畴永远不会超过整数的范畴(INT_MIN,INT_MAX)。 QGraphicsView通过调用render()可视化场景。默认状况下,通过应用惯例的QPainer和默认的渲染提醒将我的项目绘制到视区上。要在绘制项时更改QGraphicsView传递给QPainter的默认渲染提醒,能够调用setRenderHints()。 默认状况下,QGraphicsView为viewport小部件提供惯例的QWidget。能够通过调用viewport()来拜访这个小部件,也能够通过调用setViewport()来替换它。要应用OpenGL进行渲染,只需调用setViewPort(new QGLWidget)。QGraphicsView领有viewport小部件的所有权。 QGraphicsView应用QTransform反对仿射转换。能够将矩阵传递给setTransform(),也能够调用便当函数rotate()、scale()、translate()或shear()。最常见的两种转换是缩放,用于实现缩放和旋转。QGraphicsView在转换期间放弃视图核心不变。因为场景对齐(setAligment()),转换视图不会产生视觉影响。 能够应用鼠标和键盘与场景中的我的项目进行交互。QGraphicsView将鼠标和键事件转换为场景事件(继承QGraphicsSceneEvent的事件),并将它们转发到可视化的场景。最初,处理事件并对其做出反馈的是单个我的项目。例如,如果单击一个可抉择的项,该项通常会让场景晓得它已被选中,并且它也会从新绘制本人以显示一个抉择矩形。相似地,如果你点击并拖动鼠标来挪动一个可挪动的我的项目,它就是解决鼠标挪动和挪动本人的我的项目。项交互在默认状况下是启用的,能够通过调用setInteractive()来切换它。 还能够通过创立QGraphicsView的子类并从新实现鼠标和键事件处理程序来提供本人的自定义场景交互。为了简化如何以编程形式与视图中的项进行交互,QGraphicsView提供了映射函数mapToScene()和mapFromScene(),以及项拜访器items()和itemAt()。这些函数容许在视图坐标和场景坐标之间映射点、矩形、多边形和门路,并应用视图坐标在场景中查找我的项目。 QGraphicsItem具体介绍 QGraphicsItem类是QGraphicsScene中所有图形项的基类。 它为编写本人的自定义我的项目提供了轻量级的根底。这包含通过事件处理程序定义项的几何体、冲突检测、其绘制实现和项交互。QGraphicsItem是图形视图框架的一部分。 为了不便起见,Qt为最常见的形态提供了一组规范图形项。这些是: QGraphicsEllipseItem 提供椭圆项QGraphicsLineItem 提供直线项QGraphicsPathItem 提供任意门路项QGraphicsPixmapItem 提供pixmap项QGraphicsPolygonItem 提供多边形项QGraphicsRectItem 提供矩形项QGraphicsSimpleTextItem 提供简略的文本标签项QGraphicsTextItem 提供高级文本浏览器项 (补充:若是为了深度应用,倡议全副重写一个专用积攒,而后所有元素item本人写,不应用自带的。) 我的项目的所有几何信息都基于其部分坐标系。项的地位pos()是惟一不在本地坐标中操作的函数,因为它返回父坐标中的地位。图形视图坐标系详细描述了坐标系。 能够通过调用setVisible()来设置项是否应可见(即,绘制和承受事件)。暗藏我的项目也会暗藏其子项。同样,能够通过调用setEnabled()来启用或禁用项。如果禁用某个我的项目,它的所有子项也将被禁用。默认状况下,我的项目既可见又启用。若要切换是否选择项,请首先通过设置itemIsSelectable标记启用抉择,而后调用setSelected()。通常,抉择由场景切换,这是用户交互的后果。 要编写本人的图形项,首先要创立QGraphicsItem的子类,而后从实现它的两个纯虚构公共函数开始:boundingRect(),它返回该项绘制的区域的估计值,paint()实现理论绘制。 示例: ...

June 7, 2021 · 2 min · jiezi

关于qt5:案例分享Qt-modbus485调试工具读写ByteIntDIntRealDReal当前v130

若该文为原创文章,转载请注明原文出处本文章博客地址:https://blog.csdn.net/qq21497936/article/details/117398968 红瘦子(红模拟)的博文大全:开发技术汇合(蕴含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬联合等等)继续更新中...(点击传送门) 单干案例专栏:案例分享(体验Demo可下载,只定制) 前言 西门子PLC、台达PLC、法兰克机床等等多年以前玩得比拟多,有tcp/ip通信也有modbus通信,modbus又分为网络,485,232等。 医疗我的项目,焊接机器人我的项目,工控机床我的项目,数控我的项目,物联网我的项目用的挺多的,将要害的通信技术抽离进去,独自弄成工具。 需要 与各种其余行业仪器通信软件开发的通信外围模块,modbus功能模块,制作成调试工具,可满足个别状况的调试。 1.反对通过串口232,485端口进行通信; 2.反对设置关上端口的参数; 3.反对写入bool,int,dInt,real,dReal参数类型数据; 4.反对读取bool,int,dInt,real,dReal参数类型数据; 5.减少10种主题格调切换(仅用于预抉择主题格调); Demo 工具下载地址 CSDN(0积分下载):https://download.csdn.net/download/qq21497936/19236703QQ群:1047134658(点击“文件”搜寻“plcModbus ”,群内与博文同步更新) 十种主题格调切换 相干头文件源码PlcModbusMasterWidget.h #ifndef PLCMODBUSMASTERWIDGET_H#define PLCMODBUSMASTERWIDGET_H#include <QWidget>#include <QThread>#include <QDateTime>#include <QElapsedTimer>#include <QHash>#include <QFile>#include <QMessageBox>#include <QAbstractButton>#include "ModbusManager.h"namespace Ui {class PlcModbusMasterWidget;}class PlcModbusMasterWidget : public QWidget{ Q_OBJECTpublic: explicit PlcModbusMasterWidget(QWidget *parent = 0); ~PlcModbusMasterWidget();protected slots: void slot_opened(bool opened); void slot_readBitsResult(bool result, int startAddr, QList<bool> listBool); void slot_readIntsResult(bool result, int startAddr, QList<int> listInt); void slot_readDIntsResult(bool result, int startAddr, QList<int> listInt); void slot_readRealsResult(bool result, int startAddr, QList<float> listFloat); void slot_readDRealsResult(bool result, int startAddr, QList<double> listDouble); void slot_writeBitsResult(bool result, int startAddr, QList<bool> listBool); void slot_writeIntsResult(bool result, int startAddr, QList<int> listInt); void slot_writeDIntsResult(bool result, int startAddr, QList<int> listInt); void slot_writeRealsResult(bool result, int startAddr, QList<float> listFloat); void slot_writeDRealsResult(bool result, int startAddr, QList<double> listDouble);private slots: void on_comboBox_writeType_currentIndexChanged(int index); void on_lineEdit_readStartAddr_textChanged(const QString &arg1); void on_lineEdit_writeStartAddr_textChanged(const QString &arg1); void on_lineEdit_readStartAddrHex_textChanged(const QString &arg1); void on_lineEdit_writeStartAddrHex_textChanged(const QString &arg1);protected slots: void slot_buttonClicked(int index);private slots: void on_pushButton_open_clicked(); void on_pushButton_close_clicked(); void on_pushButton_read_clicked(); void on_pushButton_write_clicked(); void on_pushButton_clearM_clicked();private: Ui::PlcModbusMasterWidget *ui; QThread *_pModbusManagerThread; QElapsedTimer _elapsedTimer; QHash<int, QString> _hashInt2Str;};#endif // PLCMODBUSMASTERWIDGET_H ...

May 31, 2021 · 2 min · jiezi

关于qt5:Qt三方库开发技术一QuaZIP介绍编译和使用

若该文为原创文章,转载请注明原文出处本文章博客地址:https://blog.csdn.net/qq21497936/article/details/116561845 红瘦子(红模拟)的博文大全:开发技术汇合(蕴含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬联合等等)继续更新中…(点击传送门) Qt开发专栏:三方库开发技术 前言 Qt应用一些压缩解压性能,探讨过libzip库,zlib库,libzip库比拟原始,还有其余库,都比拟根底,而在根底库之上,又有高级封装库,Qt中的QuaZIP是一个很好的抉择。 本文次要详解QuaZIP。 QuzZip介绍 QuaZIP是Gilles Vollant的ZIP / UNZIP软件包的简略C ++包装,可用于拜访ZIP档案。 依赖库:zlib库 Qt 4无论如何都依赖于zlib,然而您将须要zlib标头来编译QuaZIP。应用Qt5有时,您还须要zlib库(例如,在Windows上)。 反对平台 QuaZIP以后已在以下平台上进行了测试: linux-g ++(Ubuntu 11.10,Qt 4.7.4)freebsd-g ++(Qt 4.0.0hpux-acc(HP-UX 11.11)hpux-g ++(HP-UX 11.11)win32-g ++(MinGW)win32-msvc2010(MS VS 2010 Express,Qt 4.8.4)win32-msvc2010(Qt Creator,Qt 5.0.1)win32-msvc2012(Qt Creator,Qt 5.2.0) 指标平台:windows Qt5.9.3 msvc2015x86编译zlip 参考文章《zlib开发笔记(一):zlib库介绍、编译和工程模板》。 下载QuaZIP 官网:http://quazip.sourceforge.net QQ群下载地址:1047134658(点击“文件”搜寻“quazip”,群内与博文同步更新) 编译QuaZIP库步骤一:下载解压 步骤二:CMake配置configure 步骤三:批改Qt版本 步骤四:增加zlib库 步骤五:CMake生成 工程 步骤六:应用Qtcreator关上quazip源码pro文件 上图退出zlib库的门路,而后编译。 模块化 Demo#include <QApplication>#include "QuaZibManager.h"#include <QDebug>#define LOG qDebug()<<__FILE__<<__LINE__int main(int argc, char *argv[]){ QApplication a(argc, argv); LOG; QuaZibManager quaZibManager; QStringList list = quaZibManager.getZipFileList("testFile.zip"); LOG; for(int index = 0; index < list.size(); index++) { LOG << list.at(index); } LOG; return a.exec();} ...

May 17, 2021 · 1 min · jiezi

关于qt5:一Halcon窗口界面上显示文字的字体尺寸样式修改

1、查看Halcon帮忙文档养成良好的查资料习惯,能够实现事倍功半。 1.1 Halcon12和Halcon20不同版本的帮忙有所不同在Halcon12中,有set_font和set_display_font两个算子,其中set_display_font是本地函数模式,所以最终的实现算子为set_font.依照不同的零碎环境下,应用办法略有不同: 不同的零碎下应用的办法不同,本来认为比较简单,间接依照文档的example来设定就行,然而win下的字体比拟多,这种办法可行,其余的零碎下未必有指定的Font类型,所以我在Linux下始终提醒的Font类型谬误;再翻一下最新版Halcon20版本的文档新版介绍简略了很多,如果只批改字体,间接应用set_system('default_font',Font)设置默认字体就行,这里还进行提醒,依据不同的零碎,获取反对的字体进行设置,最初给出了比拟简洁的example做参考。 1.2在win和LINUX下用Qt实现字体批改依据之前的帮忙文档,能够在Qt下实现字体批改 //设定Halcon窗口文字字体 HTuple hv_OS; GetSystem("operating_system",&hv_OS); if(hv_OS.TupleSubstr(0,2) == HTuple("Win")){ //办法一:间接设置Font参数 QString Font_win = "-Arial-10-*-1-*-*-1-"; QByteArray ba = Font_win.toLocal8Bit(); const char *string = ba.data(); SetFont(hv_WindowHandleCurrent,string); } else if(hv_OS.TupleSubstr(0,4) == HTuple("Linux")){ //办法二:获取零碎下的字体,抉择第一个加载应用 HTuple hv_Font,hv_FontWithSize; QueryFont(hv_WindowHandleCurrent,&hv_Font); hv_FontWithSize = HTuple(hv_Font[0]) + "-40"; SetFont(hv_WindowHandleCurrent,hv_FontWithSize); }因为在Linux下设置了好几种字体都显示谬误,所以间接应用第二种办法,获取Linux反对的字体进行设置。根据上述办法设定的成果如下 1.3相干实现Demo程序Halcon窗口显示文字字体批改

May 8, 2021 · 1 min · jiezi

关于qt5:Qt5之QGraphicsItem编写Tetris俄罗斯方块游戏

背景应用Qt5.12.9的QGraphicsItem来实现俄罗斯方块,当初是C++版本,下来还会有python版本,以及不便的接口,来接入算法,由机器人玩俄罗斯方块。 思路CustomGraphBase类继承自QGraphicsObject,提供必要的虚函数。CustomGraphTetrisBlock类继承自CustomGraphBase,实现最小方块,分边框类型(0)与方块类型(1)。CustomGraphTetrisText类继承自CustomGraphBase,显示文字,类型为5。Tetris类组合CustomGraphTetrisBlock,显示俄罗斯方块。Game类为游戏逻辑管制类。 该游戏传统的编程形式,是用一个二维数组来管制游戏空间,相似迷宫的形式。其实抉择QGraphicsItem来实现就是一种很另类的抉择,其实用gdi来做更不便,这种规模,QGraphicsItem没有劣势,只是集体学习摸索的抉择。 我没有用二维数组来管制游戏空间,而是在边际上用了一圏CustomGraphTetrisBlock来定义游戏空间,因为所有的items都能不便的在scene上检索到,所以看一个方块是否能挪动,就须要检索本人的四周是否曾经被其它方块占据。这里有一点,在方块进行旋转的时候,就要判断辨别组成本人的block和他人的方块。 效果图 要害代码剖析性能尽量内聚,类CustomGraphTetrisBlock封装小方块,Tetris类组合了Block,封装了俄罗斯方块的绝大部分操作,类Game游戏的整体流程。 CustomGraphBase自定义图元基类class CustomGraphBase : public QGraphicsObject{ Q_OBJECTpublic: CustomGraphBase();public: virtual QRectF boundingRect() const = 0; //占位区域,必须精确,能力很好的显示与革除 virtual int type() const = 0; virtual void relocate() = 0; //挪动,重定位 virtual bool isActive() { return false; };//未落地的方块 virtual int getBlockType() { return 0; }; //方块类型,次要区别边际方块};CustomGraphTetrisBlock 最小方块,组成俄罗斯方块的根本元素paint 重绘操作,须要操作边际方块,边际方块只占位,不显示。要留神prepareGeometryChange()函数的应用,不能放在这个函数中,不然会不停的重绘,占用大量CPU资源。具体原理我还没钻研透,我将其放到relocateb函数中了。 void CustomGraphTetrisBlock::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget /*= nullptr*/){ if (blockType) { painter->drawRoundedRect( 0, 0, BLOCKSIDEWIDTH, BLOCKSIDEWIDTH, 2, 2 ); } //prepareGeometryChange();}relocate元素重定位,只需将其放到scene上正确的坐标 ...

May 6, 2021 · 3 min · jiezi

关于qt5:海康摄像SDK开发笔记一海康威视网络摄像头SDK介绍与模块功能

若该文为原创文章,转载请注明原文出处本文章博客地址:https://blog.csdn.net/qq21497936/article/details/1116396032 红瘦子(红模拟)的博文大全:开发技术汇合(蕴含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬联合等等)继续更新中…(点击传送门) Qt开发专栏:三方库开发技术 前言 视频监控、人脸识别等利用中常常应用到摄像头,以后占据支流视频监控摄像头就是海康和大华两家,都可通过自家的sdk或者是onvif形式应用和管制摄像头。 本文章解说海康的sdk形式。 海康 海康(海康威视)是以视频为外围的智能物联网解决方案和大数据服务提供商,在视频行业是以后实打实的老大哥,当然还有大华,其余不多做介绍。 海康设施网络SDK下载 下载地址:https://www.hikvision.com/cn/download_61.html 在ubuntu16.04 x86_64上开发,下载SDK_Linux64版本,可查看详细描述,右上角下载: 点击下载: 解压后: 海康威视SDK自带QtDemo,不过是qt4.7版本的,笔者应用qt5版本。 海康SDK概述与应用流程初始化SDK 海康sdk有其固有的应用流程,如下图: 初始化SDK(NET_DVR_Init) 对整个网络SDK零碎的初始化,内存预调配等。 设置连贯超时工夫(NET_DVR_SetConnectTime)可选 设置SDK中的网络连接超时工夫,不调用则应用默认值。 异样回调函数(NET_DVR_SetDVRMessage或NET_DVR_SetExceptionCallBack_V30) sdk中大部分模块的性能是异步异样,海康提供此接口用于接管预览、报警、回放、通明通道和语音对讲等模块产生异样信息。用户能够在初始化 SDK 后就设置该回调函数,在应用层对各个模块异样音讯的接管和解决。 从解析服务器取得设施的 IP 地址(NET_DVR_GetDVRIPByResolveSvr_EX) 该接口提供一种在仅晓得设施名称(或 DDNS 域名)或者序列号的状况下,从解析服务器取得设施 IP 地址的办法。如:以后设施是通过拨号上网形式获取到动静 IP 地址,而运行了我公司 IPServer 软件的服务器即为解析服务器或者设施注册到我公司 DDNS 服务器上,咱们能够通过此接口输出服务器的地址、设施的名称或序列号等信息查问该设施的 IP 地址。(留神:由此看来不能达到没有任何配置的状况下,间接应用该函数搜寻到局域网内的所有摄像头信息)。 用户注册设施(NET_DVR_Login_V30) 实现用户的注册性能,注册胜利后,返回的用户 ID 作为其余功能操作的惟一标识, SDK 容许最大注册用户数为 512 个。就设施而言, V3.0 以上版本反对的设施容许有 32 个注册用户名,而且同时最多容许 128 个用户注册; V3.0 以下版本反对的设施容许有 16 个注册用户名,而且同时最多容许 128 个用户注册。 登录后才可进行性能其余性能的调用(除了报警模块不须要登录)。 开释SDK(NET_DVR_Cleanup) 不再应用sdk后,开释其应用的资源。 SDK功能模块 预览模块 从设施取实时码流,解码显示以及播放管制等性能,同时反对软解码和解码卡解码。 ...

May 4, 2021 · 1 min · jiezi

关于qt5:Qt开发技术Qt拽拖开发一拽托框架详解及Demo

若该文为原创文章,转载请注明原文出处本文章博客地址:https://blog.csdn.net/qq21497936/article/details/116292217 红瘦子(红模拟)的博文大全:开发技术汇合(蕴含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬联合等等)继续更新中…(点击传送门) Qt开发专栏:开发技术(点击传送门) 上一篇:没有了下一篇:敬请期待... 前话 Qt中的拽拖操作具体介绍。 Demo图片拽拖 控件拽拖 窗口拽拖 拽托框架(高级开发) 拖放(Drag and Drop) 拖放提供了一种简略的可视机制,用户能够应用它在应用程序之间和外部传输信息。拖放的性能相似于剪贴板的剪切和粘贴机制。 本文档形容了根本的拖放机制,并概述了在自定义控件中启用该机制的办法。许多qt的控件也反对拖放操作,例如我的项目视图和图形视图框架,以及为qt小部件和qt quick编辑控件。无关我的项目视图和图形视图的详细信息,请参见应用我的项目视图和图形视图框架的拖放。 拖放类 这些类解决拖放和必要的mime类型编码和解码。 配置 QStyleHints对象提供了一些与拖放操作相干的属性: QStyleHints::startDragTime():形容在开始拖动之前,用户必须在对象上按住鼠标按钮的工夫量(毫秒)。QStyleHints::StartDragDistance():示意在挪动被解释为拖动之前,按住鼠标按钮时用户必须挪动鼠标的间隔。QStyleHints::StartDragVelocity():示意用户挪动鼠标开始拖动的速度(以像素/秒为单位)。值为0示意没有这样的限度。 如果在控件中提供拖放反对,这些数量将提供与根底窗口零碎兼容的正当默认值,供您应用。 在Qt Quick种的拖放 文档的其余部分次要关注如何在C++中实现拖放。要在Qt疾速场景中应用拖放,请浏览Qt Quick拖放、DragEvent和DropArea项的文档,以及Qt疾速拖放示例。 拖曳(Dragging) 要开始拖动,请创立一个QDrag对象,并调用其exec()函数。在大多数应用程序中,只有在按下鼠标按钮并挪动光标肯定间隔后,能力开始拖放操作。然而,启用小部件拖动最简略办法是从新实现小部件的mousePressEvent(),并启动拖放操作: 只管用户可能须要一些工夫来实现拖动操作,但就应用程序而言,exec()函数是一个带有多个值之一的阻塞函数。这些阐明操作是如何完结的,上面将具体介绍。 留神,exec()函数不会阻塞主事件循环。 对于须要辨别鼠标单击和拖动的小部件,从新实现小部件的mousePressEvent()函数以记录拖动的开始地位是很有用的: 稍后,在mouseMoveEvent()中,咱们能够确定是否应该开始拖动,并结构一个拖动对象来解决该操作: 这种非凡的办法应用QPoint::manhattanlength()函数粗略预计鼠标单击地位和以后光标地位之间的间隔。此函数以精度换取速度,通常实用于此目标。 放下(Dropping) 要可能接管小部件上抛弃的媒体,请为小部件调用setAcceptDrops(true),并从新实现dragEnterEvent()和dropEvent()事件处理程序函数。例如,以下代码启用了QWidget子类的构造函数中的Drop事件,从而能够无效地实现Drop事件处理程序: dragEnterEvent()通常用于告诉qt小部件承受的数据类型。如果要在DragMoveEvent()和dropEvent()的从新实现中接管QDragMoveEvent或QDropEvent,则必须从新实现此函数。 报错 上面的代码显示如何从新实现DragEnterEvent(),以通知拖放零碎咱们只能解决纯文本: dropEvent()用于解包抛弃的数据,并以适宜您的应用程序的形式对其进行解决。 在以下代码中,事件中提供的文本将传递给QTextBrowser,QComboBox将填充用于形容数据的mime类型列表: 在这种状况下,咱们承受倡议的操作,而不查看它是什么。在理论应用程序中,可能须要从dropEvent()函数返回,而不承受倡议的操作,或者在操作不相干的状况下解决数据。例如,如果咱们不反对到应用程序中内部源的链接,咱们能够抉择疏忽Qt::LinkAction操作。 笼罩提议的口头 也能够疏忽提议的操作,并对数据执行其余操作。为此,咱们将在调用accept()之前应用Qt::dropAction中的首选操作调用事件对象的setDropAction()。这样能够确保应用替换删除操作而不是倡议的操作。对于更简单的应用程序,从新实现dragMoveEvent()和dragLeaveEvent()将使小部件的某些局部对搁置事件敏感,并使您可能更好地控制应用程序中的拖放。 简单小部件的子类化 某些规范Qt小部件为拖放提供了本人的反对。在对这些小部件进行子类化时,除了DragCenterEvent()和DropEvent()之外,可能还须要从新实现DragMoveEvent(),以避免基类提供默认的拖放解决,并解决您感兴趣的任何非凡状况。 拖放操作 在最简略的状况下,拖放操作的指标将接管正在拖动的数据的正本,源将决定是否删除原始数据。这由CopyAction操作形容。指标还能够抉择解决其余操作,特地是MoveAction和LinkAction操作。如果源调用QDrag::exec(),并返回MoveAction,则如果源抉择删除任何原始数据,则该源将负责删除。不应删除源小部件创立的QMimeData和QDrag对象-它们将被Qt销毁。 指标负责获取在拖放操作中发送的数据的所有权;这通常通过保留对数据的援用来实现。 如果指标了解LinkAction操作,它应该存储本人对原始信息的援用;源不须要对数据执行任何进一步的解决。拖放操作的最常见用法是在同一个小部件中执行挪动;无关此性能的详细信息,请参阅无关拖放操作的局部。 拖动操作的另一个主要用途是在应用援用类型(如text/uri-list)时,其中拖动的数据实际上是对文件或对象的援用。 增加新的拖放类型 拖放不限于文本和图像。任何类型的信息都能够在拖放操作中传输。要在应用程序之间拖动信息, 应用程序必须可能互相批示能够承受哪些数据格式以及能够生成哪些数据格式,这是通过应用mime类型实现的。 由源结构的QDrag对象蕴含一个用于示意数据的mime类型列表(从最合适的到最不适合的顺序排列),drop指标应用其中一个来拜访数据。对于常见的数据类型,便当函数解决通明应用的mime类型,然而对于自定义数据类型,必须显式地申明它们。 要对QDrag便当性能未涵盖的信息类型执行拖放操作,第一步也是最重要的一步是查找适当的现有格局:Internet调配号码管理局(IANA)在信息科学研究所(ISI)提供了MIME媒体类型的分层列表。应用规范的mime类型能够最大限度地进步应用程序与其他软件当初和未来的互操作性。要反对其余媒体类型,只需应用setData()函数设置QMimeData对象中的数据,提供残缺的mime类型和以适当格局蕴含数据的QByteArray。以下代码从标签中获取QPixmap,并将其存储为QMimeData对象中的可移植网络图形(PNG)文件: ...

April 30, 2021 · 1 min · jiezi

关于qt5:Dalsabasler相机采图实现图像格式BYTEHObject和Mat转换方法

1、概述机器视觉我的项目中,如何采集到适合的图像是我的项目的第一步,也是最重要的一步,间接关系到前面图像处理算法及最终执行的后果。所以采纳不同的工业相机成像以及如何转换成图像处理库所须要的格局成为我的项目开发中首先要思考的问题。 2、工业相机图像采集形式这里工业相机抉择就不赘述了,因为绝对于我的项目或设施来讲,须要依据我的项目须要筛选适宜的硬件,而针对图像采集也有基于SDK开发或间接采纳Halcon的相机采集助手。 2.1 相机自带的SDK采图这种形式是厂家比拟举荐的,也是比拟罕用的办法,起因之一是每个厂家对本人的产品比拟熟知,提供的SDK也是比较稳定的,而且也会有肯定的技术支持;第二个起因就是基于SDK的开发能够获取更多相机及图像的原始参数,这样在做我的项目中的灵便度也会更高,个别大一些的品牌相机的SDK和demo程序会更具体,而且针对相机封装的函数也更欠缺,这里我在我的项目中用的较多的是Dalsa和basler,国产的用的较多的是海康、京航和方诚。这里针对Dalsa和balsa的面阵相机做一下简略的介绍。(编程环境是Qt5) 2.1.1 Dalsa相机采图形式初始化相机 void CaptureThread::initCamera(){ m_AcqDevice = new SapAcqDevice(SapLocation("Nano-M2420_1", 0),false); BOOL Status = m_AcqDevice->Create(); if(Status){ qDebug()<<"相机连贯胜利"<<endl; m_Buffers = new SapBufferWithTrash(3,m_AcqDevice); m_AcqDevice->GetFeatureValue("Width",&Img_Width); m_AcqDevice->GetFeatureValue("Height",&Img_Height); // qDebug()<<"Width:"<<Img_Width<<"Height:"<<Img_Height<<endl; m_Xfer = new SapAcqDeviceToBuf(m_AcqDevice,m_Buffers,XferCallback,this); } if (!CreateObjects()) { return; }}回调函数次要是用于获取图像数据 void CaptureThread::XferCallback(SapXferCallbackInfo *pInfo){ CaptureThread *pDlg = (CaptureThread *) pInfo->GetContext(); if(pInfo->IsTrash()){ qDebug()<<"IsTrash"<<endl; return; } // qDebug()<<"相机向缓存中写入数据"<<endl; HObject hv_Current_Image; BYTE *pData; pDlg->m_Buffers->GetAddress((void**)&pData); GenImage1(&hv_Current_Image,"byte",pDlg->Img_Width,pDlg->Img_Height,(Hlong)pData); // GenImageInterleaved(&hv_Current_Image,(Hlong)pData,"rgb",pDlg->Img_Width,pDlg->Img_Height,-1,"byte",0,0,0,0,-1,0); //判断图像处理工作形式 if(pDlg->TestImg_WorkType == 0) { emit pDlg->startImgProcess(hv_Current_Image); pDlg->TestImg_WorkType = -1; } else if(pDlg->TestImg_WorkType == 1) { emit pDlg->startImgProcess(hv_Current_Image); } else{ emit pDlg->canShowImg(hv_Current_Image); } pDlg->m_Buffers->ReleaseAddress((void *)pData); pDlg->m_Buffers->Clear(pDlg->m_Buffers->GetIndex());}最初是调用Dalsa相机的采图函数来触发 ...

April 16, 2021 · 4 min · jiezi

关于qt5:pyqt5-QLabel-加边框并设置边框样式

代码# -*- coding: utf-8 -*-from PyQt5 import QtCore, QtWidgetsfrom PyQt5.QtWidgets import QFrame, QApplication, QMainWindowimport sysclass Ui_MainWindow(QMainWindow): def __init__(self,parent=None): super(Ui_MainWindow,self).__init__(parent) self.setupUi() def setupUi(self): self.setObjectName("MainWindow") self.resize(800, 600) #定义label标签 self.label = QtWidgets.QLabel(self) # 设置对象名(不是设置显示容) self.label.setObjectName("label") # 设置地位 # 最初一个参数调整行距(其实也能够看作是高度,发现*2时与按钮等高 self.label.setGeometry(QtCore.QRect(130, 240, 500, 15*2)) #设置文本显示内容 self.label.setText("文本显示内容") #边框 !!边框长度与label控件统一(如果要批改长度,只须要批改上方的setGeometry的第三个参数 # 设置边框款式 self.label.setFrameShape(QtWidgets.QFrame.Box) # 设置暗影 据说只有加了这步能力设置边框色彩。///可选款式有Raised、Sunken、Plain(这个无奈设置色彩)等 self.label.setFrameShadow(QtWidgets.QFrame.Raised) # 设置背景色彩,包含边框色彩 # self.label.setStyleSheet() self.label.setFrameShape(QFrame.Box) #设置边框款式 # 设置背景填充色彩'background-color: rgb(0, 0, 0)' # 设置边框色彩border-color: rgb(255, 170, 0); self.label.setStyleSheet('border-width: 1px;border-style: solid;border-color: rgb(255, 170, 0);background-color: rgb(100, 149, 237);') # 调整文字与边框的对齐,能够多试几个参数,比方AlignTop self.label.setAlignment(QtCore.Qt.AlignVCenter)if __name__ == '__main__': app = QApplication(sys.argv) ui = Ui_MainWindow() ui.show() sys.exit(app.exec_())后果轻易抄的色彩,审美不好,轻喷。 ...

April 9, 2021 · 1 min · jiezi

关于qt5:QT下获取Halcon图形窗口鼠标事件并执行相应操作

1、背景在视觉我的项目开发过程中碰到了须要应用Halcon进行图像算法开发的需要,预计很多视觉工程师都用到过Halcon软件开发库,然而实现Halcon算法开发后就会遇到一个问题,就是图像的显示、读写、UI交互等问题,因为Halcon具备非凡的图像文件格式HObject和数据格式HTuple,所以说须要格局转换后能力实现绝对应的操作,不过Halcon自身也有比拟实用的显示、界面交互的性能,所以如何在C++或QT下应用这些性能成为了接下来须要去钻研和实际的工作。 2、参考信息Halcon针对不同的开发环境,给出了不同的开发例程,针对图形显示及界面操作这一块,Halcon只给出了C#的相干例程,其运行后果如下: 其中能够实现在窗口界面创立矩形、圆、椭圆等形态的Region,并依据鼠标来抉择、拖动和设置尺寸,并实现设置色彩,获取坐标,region区内二值化、轮廓化等一系列后续操作。 3、指标实现在QT环境下,将Halcon窗口贴在QT的控件上,并实现上述创立和操作region的根本动作。 4、步骤4.1 Halcon库的配置自己应用的是Halcon12.0的破解版,目前调用Halcon的函数不会出错,然而我的项目中有调用新版本的Halcon库有出错情况,目前未查证是不是版本的问题,Halcon配置次要在PRO文件中增加Include和Lib的援用门路。其中HALCONROOT是环境变量中Halcon的装置门路。 #includes INCLUDEPATH += "$$(HALCONROOT)/include" INCLUDEPATH += "$$(HALCONROOT)/include/halconcpp" #libs QMAKE_LIBDIR += "$$(HALCONROOT)/lib/$$(HALCONARCH)" unix:LIBS += -lhalconcpp -lhalcon -lXext -lX11 -ldl -lpthread win32:LIBS += "$$(HALCONROOT)/lib/$$(HALCONARCH)/halconcpp.lib" \ "$$(HALCONROOT)/lib/$$(HALCONARCH)/halcon.lib"4.2 读取图像,并实现图像自适应窗体控件大小这里我首先创立了一个QHalconWindow类,而后在qt的ui界面将widget晋升为QHalconWindow类,这样就免去了Halcon窗口句柄和ui句柄的绑定,间接通过QHalconWindow类来调用就行。 qhalconwindow.h文件#include <QObject>#include <QWidget>#include "HalconCpp.h"class QHalconWindow : public QWidget{ Q_OBJECTpublic: explicit QHalconWindow(QWidget *parent = 0,long Width=0,long Height=0); virtual ~QHalconWindow(void); HalconCpp::HTuple WindowID(void) {return WinID;} //f返回窗口句柄protected: void resizeEvent(QResizeEvent*); //窗口大小尺寸调整事件private: HalconCpp::HTuple WinID; void OpenWindow(void);}Cpp文件次要是对于窗口基本操作的实现函数#include "qhalconwindow.h"using namespace HalconCpp;QHalconWindow::QHalconWindow(QWidget *parent,long Width,long Height) : QWidget(parent){ resize(Width,Height); show(); OpenWindow();}QHalconWindow::~QHalconWindow(void){ CloseWindow(WindowID());}void QHalconWindow::OpenWindow(void){ SetWindowAttr("border_width",0); SetCheck("~father"); HalconCpp::OpenWindow(0,0,100,100,(Hlong)winId(),"visible","",&WinID); SetCheck("father");}//批改窗口尺寸void QHalconWindow::resizeEvent(QResizeEvent *){ SetWindowExtents(WindowID(),0,0,width(),height());}参考Halcon中对于SetDrawingObjectCallback函数的形容,须要在c++上面调用时,调用C++格局的函数,即下图的Void的回调函数指针。然而这个回调函数在程序中须要定义为一个全局函数,次要根据是Halcon中介绍,如下:所以依据这些需要实现Halcon窗口中绘制矩形、圆形和直线的操作4.3 次要的图形绘制和贴图操作见如下代码,其中重点为全局函数的创立来实现抉择Select、拖拽Drag和尺寸Resize事件响应。 ...

March 25, 2021 · 3 min · jiezi

关于qt5:项目实战Qt数据分析处理平台兼容各国产麒麟系统上万文件批量导入折线图散点图正态分布图分析处理导出等

若该文为原创文章,转载请注明原文出处本文章博客地址:https://blog.csdn.net/qq21497936/article/details/114710650长期继续带来更多我的项目与技术分享,征询请加QQ:21497936、微信:yangsir198808 红瘦子(红模拟)的博文大全:开发技术汇合(蕴含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬联合等等)继续更新中…(点击传送门) 开发专栏:商业我的项目实战 需要 1.创立原始数据我的项目,我的项目下能够创立产品,产品自从创立四个阶段,阶段能够导入各自数据格式的原始文件; 2.创立原始数据我的项目和产品的时候,参数配置文件、胜利配置文件、胜利数据也会创立对应的我的项目和产品; 3.树形图,反对创业项目、批改我的项目、删除我的项目; 4.树形图,我的项目下,反对守业产品、批改产品‘删除产品; 5.树形图,产品下,主动产生四个阶段,反对创立新的阶段,批改原有阶段,删除某个阶段; 6.大批量到处单个我的项目产品阶段的文件,并动态显示导入过程;’ 7.可对原始数据进行二维图的数据二维图散布变动剖析,并可动静调整文件和文件对应的参数; 8.可对胜利数据进行多文件综合剖析,蕴含各文件和各文件下的解析格局,生成对应的关联关系; 9.在应用二维图、散点图、正态分布图进行剖析时,反对区域缩放,反对显示暗藏,反对截图保留,反对导出当先正在显示的二维图原始数据(暗藏的点和行数据不导出) 10.应用sqlite3数据库; 11.反对各windows版本和国产河汉麒麟零碎; (其余负载逻辑解决与小性能不一一列举) Demo 若该文为原创文章,转载请注明原文出处本文章博客地址:https://blog.csdn.net/qq21497936/article/details/114710650

March 12, 2021 · 1 min · jiezi

关于qt5:项目实战Qt-树莓派3B-智能笔筒系统

若该文为原创文章,转载请注明原文出处本文章博客地址:https://blog.csdn.net/qq21497936/article/details/114293412长期继续带来更多我的项目与技术分享,征询请加QQ:21497936、微信:yangsir198808 红瘦子(红模拟)的博文大全:开发技术汇合(蕴含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬联合等等)继续更新中…(点击传送门) 开发专栏:商业我的项目实战 需要 1.基于树莓派3B+,应用Qt语言开发; 2.搜寻wifi包含信并显示信号强度,能够点击输出明码连贯, 3.显示以后日期、温度、湿度、气温、PM2.5; 4.多个闹钟,具备闹钟性能; 5.笔筒能够绑定手机号码,用户信息; 6.拉取课程表并显示课程表; 7.日历性能,显示阳历、阴历,并反对代办记事揭示; 8.收到云端留言音讯,并可点击查看; 相干博客 《树莓派开发笔记(一):动手树莓派3b,胜利运行树莓派零碎》 《树莓派开发笔记(二):树莓派Qt编译和宿主机Qt穿插编译》 《树莓派开发笔记(三):更便捷的开发,windows下和ubuntu下远程桌面至树莓派》 《树莓派开发笔记(四):更便捷的开发,qt近程运行(主机qt开发一键近程运行到指标机上)》 树莓派3B+ Demo 若该文为原创文章,转载请注明原文出处本文章博客地址:https://blog.csdn.net/qq21497936/article/details/114293412

March 2, 2021 · 1 min · jiezi

关于qt5:项目实战Qt中英文输入软键盘支持Qt4Qt5触摸和键鼠混合输入等

若该文为原创文章,转载请注明原文出处本文章博客地址:https://blog.csdn.net/qq21497936/article/details/111831179长期继续带来更多我的项目与技术分享,征询请加QQ:21497936、微信:yangsir198808 红瘦子(红模拟)的博文大全:开发技术汇合(蕴含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬联合等等)继续更新中…(点击传送门) 开发专栏:我的项目实战 需要 1. 全屏软键盘; 2. 输出英文; 3. 输出中文; 4. 反对触摸、键盘和输出混合输入; 5. 目前有彩色系皮肤; 6. Qt4和Qt5辨别2个版本; Demo:Qt5 CSDN(粉丝免积分下载):https://download.csdn.net/download/qq21497936/13945327 QQ群:1047134658(点击“文件”搜寻“softKeyboard”,群内与博文同步更新) Demo:Qt4 移植到MCGS嵌入式工控机上 V1.0.0 Demo代码 可视化的布局,以便于定制批改,所见即所得: KeyBoardWidget.h #ifndef KEYBOARDWIDGET_H#define KEYBOARDWIDGET_H#include <QWidget>#include <QPushButton>#include <QLabel>namespace Ui {class KeyBoardWidget;}class KeyBoardWidget : public QWidget{ Q_OBJECTprivate: enum INPUT_MODE { INPUT_MODE_ZH = 0x01, INPUT_MODE_EN, INPUT_MODE_SYMB, };public: explicit KeyBoardWidget(QWidget *parent = 0); ~KeyBoardWidget();public: void clearChineseCache(); void setKeyPressEvent(QKeyEvent *event);signals: void signal_sendKeyToFocusItem(QString keyText);protected: void updateChineseCharactersButtonState(); void switchLanguage(int inputMode); void searchChineseCharacters(int currentpage);protected slots: void slot_characterButtonsClicked(); void slot_switchLanguage(); void slot_backspace(); void slot_blankspace(); void slot_chineseCharacterSelected(); void slot_chineseCharacterPrevious(); void slot_chineseCharacterNext(); void slot_enter(); void slot_upper(); void slot_symbols(); void slot_emoji(); void slot_hideKeyboard();protected: void updateKeyboard();protected: void mousePressEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void showEvent(QShowEvent *event); void hideEvent(QHideEvent *event);private: Ui::KeyBoardWidget *ui;private: QList<QPushButton*> _listCharacterBtns; QList<QPushButton*> _listChineseCharactersBtns; INPUT_MODE _currentMode; INPUT_MODE _lastMode; bool _upperMode; int _symbolPage; QFont _font;private: static QString _strKeyboradCharacters; static QString _strKeyBoradSymbols[];};#endif // KEYBOARDWIDGET_HKeyBoardWidget.cpp ...

January 4, 2021 · 3 min · jiezi

关于qt5:项目实战Qt中英文输入软键盘支持Qt4Qt5触摸和键鼠混合输入等

若该文为原创文章,转载请注明原文出处本文章博客地址:https://blog.csdn.net/qq21497936/article/details/111831179长期继续带来更多我的项目与技术分享,征询请加QQ:21497936、微信:yangsir198808 红瘦子(红模拟)的博文大全:开发技术汇合(蕴含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬联合等等)继续更新中…(点击传送门) 开发专栏:我的项目实战 需要 1. 全屏软键盘; 2. 输出英文; 3. 输出中文; 4. 反对触摸、键盘和输出混合输入; 5. 目前有彩色系皮肤; 6. Qt4和Qt5辨别2个版本; Demo:Qt5 CSDN(粉丝免积分下载):https://download.csdn.net/download/qq21497936/13945327 QQ群:1047134658(点击“文件”搜寻“softKeyboard”,群内与博文同步更新) Demo:Qt4 移植到MCGS嵌入式工控机上 V1.0.0 Demo代码 可视化的布局,以便于定制批改,所见即所得: KeyBoardWidget.h #ifndef KEYBOARDWIDGET_H#define KEYBOARDWIDGET_H#include <QWidget>#include <QPushButton>#include <QLabel>namespace Ui {class KeyBoardWidget;}class KeyBoardWidget : public QWidget{ Q_OBJECTprivate: enum INPUT_MODE { INPUT_MODE_ZH = 0x01, INPUT_MODE_EN, INPUT_MODE_SYMB, };public: explicit KeyBoardWidget(QWidget *parent = 0); ~KeyBoardWidget();public: void clearChineseCache(); void setKeyPressEvent(QKeyEvent *event);signals: void signal_sendKeyToFocusItem(QString keyText);protected: void updateChineseCharactersButtonState(); void switchLanguage(int inputMode); void searchChineseCharacters(int currentpage);protected slots: void slot_characterButtonsClicked(); void slot_switchLanguage(); void slot_backspace(); void slot_blankspace(); void slot_chineseCharacterSelected(); void slot_chineseCharacterPrevious(); void slot_chineseCharacterNext(); void slot_enter(); void slot_upper(); void slot_symbols(); void slot_emoji(); void slot_hideKeyboard();protected: void updateKeyboard();protected: void mousePressEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void showEvent(QShowEvent *event); void hideEvent(QHideEvent *event);private: Ui::KeyBoardWidget *ui;private: QList<QPushButton*> _listCharacterBtns; QList<QPushButton*> _listChineseCharactersBtns; INPUT_MODE _currentMode; INPUT_MODE _lastMode; bool _upperMode; int _symbolPage; QFont _font;private: static QString _strKeyboradCharacters; static QString _strKeyBoradSymbols[];};#endif // KEYBOARDWIDGET_HKeyBoardWidget.cpp ...

December 29, 2020 · 3 min · jiezi

关于qt5:xml开发笔记一tinyXml2库介绍编译和工程模板

若该文为原创文章,转载请注明原文出处本文章博客地址:https://blog.csdn.net/qq21497936/article/details/111828450长期继续带来更多我的项目与技术分享,征询请加QQ:21497936、微信:yangsir198808 红瘦子(红模拟)的博文大全:开发技术汇合(蕴含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬联合等等)继续更新中…(点击传送门) Qt开发专栏:三方库开发技术 前言 Qt开发Xml相干技术,应用到tinyxml2库。 TinyXML TinyXML是一个简略的、小的C++的XML解析器,能够集成到其余程序中。它是ROS的规范XML解析器。 最新的曾经是TinyXML2版本了。 github下载地址:https://github.com/leethomason/tinyxml2 CSDN下载地址:https://download.csdn.net/download/qq21497936/13944558 QQ群:1047134658(点击“文件”搜寻“tinyxml2”,群内与博文同步更新) TinyXML编译步骤一:解压 步骤二:Cmake配置 间接强上,先批改C编译器的 而后批改CXX编译器的 步骤三:生成工程 步骤四:命令行编译 步骤五:装置install 模块化 Demovoid TinyXmlManager::testEnv(){ // 测试创立一个简略html文件 tinyxml2::XMLDocument doc; // 增加第一行 doc.Parse("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); // 增加第一个节点 // 增加第一个节点中的属性 <ofd:OFD xmlns:ofd="http://www.ofdspec.org" DocType="OFD" Version="1.0"> tinyxml2::XMLElement * pXmlElement; pXmlElement = doc.NewElement("ofd:OFD"); pXmlElement->SetAttribute("xmlns:ofd", "http://www.ofdspec.org"); pXmlElement->SetAttribute("DocType", "OFD"); pXmlElement->SetAttribute("Version", "1.0"); // 子节点 <ofd:DocBody> tinyxml2::XMLElement * pXmlElement2; pXmlElement2 = doc.NewElement("ofd:DocBody"); pXmlElement2->SetAttribute("Author", "红模拟"); pXmlElement2->SetAttribute("QQ", 21497936); pXmlElement2->SetAttribute("Blog", "https://blog.csdn.net/qq21497936"); pXmlElement->InsertEndChild(pXmlElement2); doc.InsertEndChild(pXmlElement); // 保留 doc.SaveFile("1.xml");} ...

December 27, 2020 · 1 min · jiezi

关于qt5:Qt实现一个简单的计算器

Qt实现一个简略的计算器作者:hackett 微信公众号:加班猿 一、UI界面版运行成果:输出num1和num2抉择+-*/点击计算即可 UI界面设计: 3个lineEdit(lineEditNum1,lineEditNum2,lineEditSum) 2个PushButton(buttonClear,ButtonCalc) 1个comboBox 1个label 布局: 3个lineEdit和1个comboBox、1个label程度布局 2个PushButton和一个弹簧程度布局 最初整体布局即可 main.cpp #include "mainwindow.h"#include <QApplication>int main(int argc, char *argv[]){    QApplication a(argc, argv);    MainWindow w;    w.show();    return a.exec();}mainwindow.cpp #include "mainwindow.h"#include "ui_mainwindow.h"#include <QDebug>#include <QMessageBox>MainWindow::MainWindow(QWidget *parent) :    QMainWindow(parent),    ui(new Ui::MainWindow){    ui->setupUi(this);}MainWindow::~MainWindow(){    delete ui;}void MainWindow::on_buttonCalc_clicked(){    double num1 = ui->lineEditNum1->text().toDouble();//获取num1的值    double num2 = ui->lineEditNum2->text().toDouble();//获取num2的值    uint8_t index = ui->comboBox->currentIndex();   //获取下拉框的下标0 +, 1 - ,2 *, 3 /    double result = 0.0;    switch (index) {    case 0:        result = num1 + num2;        break;    case 1:        result = num1 - num2;        break;    case 2:        result = num1 * num2;        break;    case 3:        if(num2 == 0)        {            QMessageBox::about(this,"留神","除数不能为0");            return;        }        result = num1 / num2;        break;    default:        break;    }    ui->lineEditSum->setText(QString::number(result));}void MainWindow::on_buttonClear_clicked(){    ui->lineEditNum1->clear();    ui->lineEditNum2->clear();    ui->lineEditSum->clear();}mainwindow.h #ifndef MAINWINDOW_H#define MAINWINDOW_H#include <QMainWindow>namespace Ui {class MainWindow;}class MainWindow : public QMainWindow{    Q_OBJECTpublic:    explicit MainWindow(QWidget *parent = 0);    ~MainWindow();private slots:    void on_buttonCalc_clicked();//计算结果槽函数    void on_buttonClear_clicked();//革除输入框槽函数private:    Ui::MainWindow *ui;};#endif // MAINWINDOW_H二、纯代码版注:只能两个数独自加减乘除,不能间断运算,按‘ = ’从新开始两个数运算 main.cpp #include "calc.h"#include <QApplication>int main(int argc, char *argv[]){    QApplication a(argc, argv);    Calc w;    w.show();    return a.exec();}calc.cpp #include "calc.h"#include <QHBoxLayout>#include <QVBoxLayout>#include <QLineEdit>#include <QSizePolicy>#include <QDebug>Calc::Calc(QWidget *parent) :    QWidget(parent){    //获取字体QFont    QFont font = this->font();    font.setPixelSize(30);    this->setFont(font);    //保留键盘值    QString keys="789-456*123/0.+=";    QVBoxLayout *vbox = new QVBoxLayout();    QSizePolicy qsPolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);    for(int i=0; i<4; i++)    {        QHBoxLayout *hbox = new QHBoxLayout();        for(int j=0; j<4; j++)        {            buttons[i*4+j] = new QToolButton(this);            //设置文本            buttons[i*4+j]->setText(keys.mid(i*4+j, 1));            hbox->addWidget(buttons[i*4+j]);            //策略设置            buttons[i*4+j]->setSizePolicy(qsPolicy);            //把按钮触发信号关联槽函数            connect(buttons[i*4+j], SIGNAL(clicked(bool)),this, SLOT(buttons_chick()));        }        //把程度布局管理器增加到垂直布局管理器中        vbox->addLayout(hbox);    }    //创立一个输入框    edit = new QLineEdit(this);    edit->setSizePolicy(qsPolicy);    edit->setMaximumHeight(60);    edit->setAlignment(Qt::AlignRight);    QVBoxLayout *allVbox = new QVBoxLayout(this);    allVbox->addWidget(edit);    allVbox->addLayout(vbox);    //初始化    firstNumber.clear();    secondNumber.clear();    calcflag = 0;}Calc::~Calc(){}void Calc::input_data(QString str){    if(calcflag == 0)    {        firstNumber.append(str);        edit->setText(firstNumber);    }else    {        secondNumber.append(str);        edit->setText(secondNumber);    }}void Calc::buttons_chick(){    //通过信号发送者获取按钮对象    QToolButton *button = (QToolButton*)sender();    //qDebug()    QString str = button->text();    QString datastr = ".0123456789";    QStringList typestr;    typestr<<"+"<<"-"<<"*"<<"/";    if(datastr.indexOf(str) >= 0)//获取按键值    {        input_data(str);    //输出数据    }else if(typestr.indexOf(str)>=0)    {        calcflag = typestr.indexOf(str)+1;//获取运算符号type    }else //=    {        double result = 0.0;        switch (calcflag) {        case 1:            result = firstNumber.toDouble()+secondNumber.toDouble();            break;        case 2:            result = firstNumber.toDouble()-secondNumber.toDouble();            break;        case 3:            result = firstNumber.toDouble()*secondNumber.toDouble();            break;        case 4:            result = firstNumber.toDouble()/secondNumber.toDouble();            break;        default:            break;        }        edit->setText(QString::number(result));        calcflag = 0;        firstNumber.clear();        secondNumber.clear();    }}calc.h #ifndef CALC_H#define CALC_H#include <QWidget>#include <QToolButton>#include <QLineEdit>class Calc : public QWidget{    Q_OBJECTpublic:    explicit Calc(QWidget *parent = 0);    ~Calc();    void input_data(QString str);    protected slots:    void buttons_chick();//按键槽函数private:        QToolButton *buttons[16];   //按钮数组    QLineEdit *edit;            //输入框    QString firstNumber;        //记录输出第一个数值    QString secondNumber;       //记录输出第一个数值    int calcflag;               //1-add, 2-sub, 3-mul, 4-div};#endif // CALC_H 如果你感觉文章还不错,记得"点赞关注" 关注我的微信公众号【 加班猿 】能够获取更多内容

October 29, 2020 · 1 min · jiezi

关于qt5:Qt中修改名称

Qt中.ui.h.cpp等文件名能够间接在工程栏右键rename然而.h文件中ifndef define并没有同步扭转,须要手动批改 界面类名、变量名等不可间接批改,该当采纳以下步骤:名称上右键-rafactor(重构器)-rename-下方窗口间接批改 如果改变较多倡议改一个保留一次,有些会影响后续改变

October 7, 2020 · 1 min · jiezi

关于qt5:PyQt5-画图板

PyQt5 画图板次要技术PyQt5qtDesigneropenCV次要性能绘画 画笔油漆桶直线矩形椭圆橡皮擦图片解决 旋转、翻转亮度、饱和度、对比度、色调调节灰度化二值化反相(反色)浮雕边缘检测含糊锐化具体代码github仓库 实现过程遇到的问题在pycharm上应用qtDesigner配置qtDesigner 配置UIC 参考 Mac下pycharm+qtdesigner环境搭建 绘图时图像不能留存或重影问题采取双缓冲绘图办法 咱们再增加一个辅助画布,如果正在绘图,也就是鼠标按键还没有开释的时候,就在这个辅助画布上绘图,只有当鼠标按键开释的时候,才在真正的画布上绘图 参考2D绘图(八)双缓冲绘图 油漆桶Flood Fill算法问题泛洪算法—Flood Fill,用于确定连贯到多维数组中给定节点的区域。 基本原理就是从一个像素点登程,以此向周边的像素点裁减着色,直到图形的边界。 实现办法包含传统递归形式dfs、bfs和描述线算法(Scanline Fill)等 在QImage上实现效率很低,因为getPixel操作很慢,能够进一步优化 def getPixel(x,y,pixels,w): i = (x + (y * w)) * 4 return pixels[i:i + 3]# 油漆桶def floodFill(image,pos): fillPositions = [] w, h = image.width(), image.height() pixels = image.bits().asstring(w * h * 4) targetColor = getPixel(pos.x(), pos.y(), pixels, w) haveSeen = set() queue = [(pos.x(), pos.y())] while queue: x, y = queue.pop() if getPixel(x, y,pixels,w) == targetColor: fillPositions.append((x,y)) queue.extend(getCardinalPoints(haveSeen, (x, y),w,h)) return fillPositionsdef getCardinalPoints(haveSeen, centerPos,w,h): points = [] cx, cy = centerPos for x, y in [(1, 0), (0, 1), (-1, 0), (0, -1)]: xx, yy = cx + x, cy + y if (xx >= 0 and xx < w and yy >= 0 and yy < h and (xx, yy) not in haveSeen): points.append((xx, yy)) haveSeen.add((xx, yy)) return points参考Implementing QPainter flood fill in PyQt5/PySide ...

September 30, 2020 · 2 min · jiezi

关于qt5:项目实战QtFfmpegOpenCV相机程序打开摄像头分辨率调整翻转旋转亮度拍照录像回放图片回放录像

若该文为原创文章,未经容许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062本文章博客地址:https://blog.csdn.net/qq21497936/article/details/108489004 红瘦子(红模拟)的博文大全:开发技术汇合(蕴含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬联合等等)继续更新中…(点击传送门) 开发专栏:我的项目实战(点击传送门)OpenCV开发专栏(点击传送门) 需要 嵌入式windows设施上的相机程序。 关上摄像头,兼容多种摄像头,摄像头分辨率切换(摄像头治理)。 对图像进行翻转、旋转、亮度调整(图像根本算法治理) 对调整后的图像进行拍照、延时拍照。 对调整后的图像进行录像(编码录制)。 对照片和录像进行回看(图片浏览器、视频播放器) 长时间运行稳固。 Demo 体验下载地址 CSDN:https://download.csdn.net/download/qq21497936/12827160 QQ群:1047134658(点击“文件”搜寻“camera”,群内与博文同步更新) 原理 应用ffmpeg解决摄像头、应用OpenCV解决录像和播放; 相干博客《我的项目实战:Qt+ffmpeg摄像头检测工具》《我的项目实战:Qt+OpenCV视频播放器(反对播放器操作,如暂停、复原、进行、工夫、进度条拽托等)》《OpenCV开发笔记(四):OpenCV图片和视频数据的读取与存储》《FFmpeg开发笔记(一):ffmpeg介绍、windows开发环境搭建(mingw和msvc)》 v1.5.0性能关上摄像头,兼容多种摄像头,摄像头分辨率切换(摄像头治理)。对图像进行翻转、旋转、亮度调整(图像根本算法治理)对调整后的图像进行拍照、延时拍照。对调整后的图像进行录像(编码录制)。对照片和录像进行回看(图片浏览器、视频播放器) Demo外围代码FfmpegCameraManager.h:摄像头治理类 #ifndef FFMPEGCAMERAMANAGER_H#define FFMPEGCAMERAMANAGER_H/************************************************************\ * 控件名称: FfmpegCameraManager, ffmpeg治理类(用于摄像头操作) * 控件形容: * 1.关上摄像头 * 2.反对动静切换分辨率 * 作者:红模拟 联系方式:QQ21497936 * 博客地址:https://blog.csdn.net/qq21497936 * 日期 版本 形容 * 2018年09年14日 v1.0.0 ffmpeg模块封装空类 * 2020年09年05日 v1.1.0 ffmpeg关上摄像头,反对的动静分辨率切换 * 2020年09年08日 v1.2.0 兼容各种摄像头,解决内存溢出bug,对最高帧率做了反对范畴内的限度 * 限度帧率个别为25fps(除非最大小于25fps或者最小大于25fps)\************************************************************/#include <QObject>#include <QString>#include <QDebug>#include <QTimer>#include <QThread>#include <QImage>#include <QProcess>#include <QMessageBox>#include <QDateTime>extern "C" { #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libswscale/swscale.h" #include "libavdevice/avdevice.h" #include "libavformat/version.h" #include "libavutil/time.h" #include "libavutil/mathematics.h" #include "libavformat/avformat.h" #include "libswscale/swscale.h" #include "libswresample/swresample.h" #include "errno.h" #include "error.h"}#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("hh:mm:ss:zzz")class FfmpegCameraManager : public QObject{ Q_OBJECTpublic:public: explicit FfmpegCameraManager(QObject *parent = nullptr);signals: void signal_captureOneFrame(QImage image);public: static QString getAvcodecConfiguration();public: bool init(); bool openUsbCamera(); QString getUsbCameraName(); QList<QString> getUsbCameraInfo(); int getCurrentFps(); int getCurrentSizeFpsIndex(); QList<QSize> getListSize() const;public slots: void slot_start(); void slot_stop(); void slot_setSizeFps(int index);protected slots: void slot_captureOneFrame();signals:public slots:private: static bool _init; AVFormatContext *_pAVFormatContext; // 全局上下文 AVInputFormat *_pAVInputFormat; AVDictionary* _pAVDictionary; // 关上编码器的配置 AVCodecContext *_pAVCodecContextForAudio; // 音频解码器上下文 AVCodecContext *_pAVCodecContextForVideo; // 视频解码器上下文(不带音频) AVCodec * _pAVCodecForAudio; // 音频解码器 AVCodec * _pAVCodecForVideo; // 视频解码器(不带音频) int _streamIndexForAudio; // 音频流序号 int _streamIndexForVideo; // 视频流序号 SwrContext *_pSwrContextForAudio; // 音频转换上下文 bool _running; bool _first; bool _opened; uint8_t *_pOutBuffer; AVFrame * _pFrame; AVFrame * _pFrameRGB; AVPacket *_pAVPacket; SwsContext *_pSwsContext; int _videoIndex; QString _cameraDescription; QList<QSize> _listSize; QList<int> _listFps; QList<QString> _listSizeFpsInfo; int _currentSizeFpsIndex;};#endif // FfmpegCameraManager_HFfmpegCameraManager.cpp:摄像头治理类 ...

September 9, 2020 · 4 min · jiezi

关于qt5:qt编译遇到FoundationFoundationh-file-not-found

在mac上编译qt我的项目都会用xcode,个别先要执行以下几步: 关上qt装置目录,Qt5.5.1/5.5/clang_64/mkspecs/features/mac下,编辑default_pre.prf文件,搜寻xcrun,isEmpty($$list($$system("/usr/bin/xcrun -find xcrun 2>/dev/null")))) 批改为:isEmpty($$list($$system("/usr/bin/xcrun -find xcodebuild 2>/dev/null")))) 保留退出 2.关上终端,输出指令:sudo xcode-select -switch /Applications/Xcode.app/Contents/Developer 而后输出明码 3.关上终端,输出指令:sudo xcodebuild -license 按回车 按q ,而后输出agree 回车 以上步骤实现,根本就能够通过qtCreator来编译运行qt我的项目了。 然而降级xcode后,发现编译过程中报'Foundation/Foundation.h' file not found这个错 解决办法如下:1.找到 /path/Qt5.5.1/5.5/clang_64/mkspecs/qdevice.pri这个文件关上编辑,在文件开端追加一句!host_build:QMAKE_MAC_SDK=macosx10.14至于这个10.14是怎么来的呢?/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs在这个文件夹下,能看到两个文件夹这个10.14就是从这来的。实现这一步,就能够欢快的编译通过了。

August 12, 2020 · 1 min · jiezi

关于qt5:Qt修改类名以及修改项目名的方法

**这一篇文章想要介绍的是如何在Qt Creator中批改一个曾经创立好的Qt我的项目的“项目名称”以及“类名”。-------------------------------------------------------------**https://blog.csdn.net/L_0x0b/article/details/97293747?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param

July 29, 2020 · 1 min · jiezi

关于qt5:Qt修改类名以及修改项目名的方法

**这一篇文章想要介绍的是如何在Qt Creator中批改一个曾经创立好的Qt我的项目的“项目名称”以及“类名”。-------------------------------------------------------------**https://blog.csdn.net/L_0x0b/article/details/97293747?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param

July 29, 2020 · 1 min · jiezi

QWaitCondition实现生产者与消费者

The QWaitCondition class provides a condition variable for synchronizing threads.//为同步线程提供条件变量 bool QWaitCondition::wait(QMutex *lockedMutex, unsigned long time = ULONG_MAX)Releases the lockedMutex and waits on the wait condition.//开释lockedMutex并期待条件 void QWaitCondition::wakeAll()Wakes all threads waiting on the wait condition.激活所有期待 期待条件的thread include <QtCore>include <iostream>const int DataSize = 100000;const int BufferSize = 4096;char buffer[BufferSize]; QWaitCondition bufferIsNotFull;QWaitCondition bufferIsNotEmpty;QMutex mutex;int usedSpace = 0; class Producer : public QThread{public: void run();}; void Producer::run(){ for (int i = 0; i < DataSize; ++i) { mutex.lock(); while (usedSpace == BufferSize)//曾经填满了缓冲区,是满的 bufferIsNotFull.wait(&mutex); //期待 bufferIsNotFull /***还有空间填充 **/ buffer[i % BufferSize] = "ACGT"[uint(std::rand()) % 4]; ++usedSpace; bufferIsNotEmpty.wakeAll();//填充了之后,缓存区是非空的,会唤醒期待bufferIsNotEmpty的线程 mutex.unlock();}} ...

July 11, 2020 · 1 min · jiezi

QUNUSED

Q_UNUSED() 没有实质性的作用,用来避免编译器警告 未使用的变量for example:int transition::getSTL(int type){ Q_UNUSED(type); return 123;} 相关问题处理:如果编译中出现以下警告: warning: unused parameter ‘arg1′ [-Wunused-parameter]原因是由于函数参数未使用,这在程序当中有时候很正常;所以个人认为此警告意义不大,可以取消; 方法一:在提示警告函数里面添加Q_UNUSED(arg1);方法二:在pro工程文件最后加入如下代码:QMAKE_CXXFLAGS += -Wno-unused-parameter

July 8, 2020 · 1 min · jiezi

QT简单自定义弹出提示框非模态数秒后自动消失

目标效果:一个提示信息框,创建后显示提示信息,一定时间后自动消失,不阻塞原来窗口。 思路: 自定义一个控件,继承自QWidget,构造时设置定时器,时间到则自我销毁。 ### 实现代码代码一共两个文件,.h/.uiReminderWidget.h #pragma once#include <QWidget>#include <QTimer>#include "ui_ReminderWidget.h"class ReminderWidget : public QWidget{ Q_OBJECTpublic: ReminderWidget(QString text="",QWidget *parent = Q_NULLPTR): QWidget(parent) { ui.setupUi(this); //设置去掉窗口边框 this->setWindowFlags(Qt::FramelessWindowHint); //text为要显示的信息 ui.label->setText(text); //设置定时器,到时自我销毁 QTimer* timer = new QTimer(this); timer->start(1500);//时间1.5秒 timer->setSingleShot(true);//仅触发一次 connect(timer, SIGNAL(timeout()), this, SLOT(onTimeupDestroy())); } ~ReminderWidget(){}private slots: void onTimeupDestroy(){ delete this; }private: Ui::ReminderWidget ui;};ReminderWidget.ui 只有一个名为label的QLabel。使用方法void Reminder::onPushBtn() { //新建的时候注意不要设置父对象,否则它不会单独显示出来,而是显示在父对象中。 ReminderWidget* p_widget = new ReminderWidget("提示信息"); //简单计算一下其显示的坐标 int x, y; x = this->pos().x() + this->width() / 2 - p_widget->width() / 2; y = this->pos().y() + 40; //设置控件显示的位置 p_widget->setGeometry(x,y, p_widget->width(),p_widget->height()); p_widget->show();}

July 4, 2020 · 1 min · jiezi

qt的软件使用了mysql在本机可以使用但是发布到别的机器上出现运行错误driver-not-load

第一点windeployqt.exe text.exe 会生成sqldrivers,在此目录下有qsqlmysql.dll第二点: mysql安装目录的bin下libcrypto-1_1-x64.dll libssl-1_1-x64.dll,安装目录的lib下libmysql.dll放到和exe同级目录下.第三点:运行mysql时,发现系统缺少vcruntime140_1.dll,你的mysql都不能运行,那qt肯定也不行啊;所以要先搞vcruntime140_1.dll到C:WindowsSystem32

July 3, 2020 · 1 min · jiezi

qt-designer的插件

release必须要release下,把dll复制到C:QtQt5.13.05.13.0mingw73_64pluginsdesigner 然后就可以在designer中看到自定义的插件 点击帮助-----关于插件 就可以看到插件 debug与release生成库的区别debug下的dll库末尾带d release:::customwidgetplugin.dll libcustomwidgetplugin.a debug:: customwidgetplugind.dll libcustomwidgetplugind.a

June 30, 2020 · 1 min · jiezi

Qt5的插件

注意QProxyStyle qt4的windowsstyle已废弃 在定义中使用Q_PLUGIN_METADATA,与qt4的不同class SimpleStylePlugin : public QStylePlugin{ Q_OBJECTQ_PLUGIN_METADATA(IID "org.qt-project.Qt.QStyleFactoryInterface" FILE "simplestyle.json")public: SimpleStylePlugin() {}QStringList keys() const;QStyle *create(const QString &key) override;}; 添加Json文件 simplestyle.json{ "Keys": [ "simplestyle" ]} 源文件//! [0]QStringList SimpleStylePlugin::keys() const{ return QStringList() << "SimpleStyle";}//! [0] //! [1]QStyle *SimpleStylePlugin::create(const QString &key){ if (key.toLower() == "simplestyle") return new SimpleStyle;return 0;}

June 28, 2020 · 1 min · jiezi

Qt中实现文本省略…

QFontMetrics类的elidedText()函数可以实现文本省略功能,假设有标签需要省略,如下所示: QString str = ui->label->fontMetrics().elidedText(string, Qt::ElideRight, 180);ui->label->setText(str);参数1,待省略文本参数2,省略模式,即…出现的位置 Qt::ElideLeft左边, Qt::ElideMiddle中间, Qt::ElideRight右边参数3, 可显示的字符串长度

September 8, 2019 · 1 min · jiezi

Qt中几个常用的标准对话框

/* * 这是几个标准对话框的使用方法 * 可以通过按钮触发槽,进而创建标准对话框对象 * 创建对象后所需操作仅仅是设置几个参数 */#include <QDebug>#include <QColorDialog> //颜色对话框#include <QFileDialog> //文件对话框#include <QFontDialog> //字体对话框#include <QInputDialog> //输入对话框#include <QProgressDialog> //进度对话框选取颜色的对话框 void MyWidget::on_pushButton_clicked(){ QColor color = QColorDialog::getColor(Qt::red, this, "颜色框"/*, QColorDialog::ShowAlphaChannel*/); //调用颜色对话框的静态函数,优点是不用创建对象 //前3参数为初始颜色,父窗口,对话框标题, //注释掉的可选参数功能是在对话框中显示透明度选项, qDebug()<< "color: " << color;//调试用 // qDebug的输出比如:color: QColor(ARGB 1, 0, 0, 0),分别是透明度alpha,红绿蓝 //alpha默认值1表示完全不透明,0是完全透明,三基色0~1对应0~255 /* //也可以创建对象,设置方面更灵活 QColorDialog dialog(Qt::red, this); //创建对象 dialog.setOption(QColorDialog::ShowAlphaChannel); dialog.exec(); //模态方式运行 QColor color = dialog.currentColor(); //获取当前颜色 qDebug() << "color: " <<color; //输出颜色信息 */}文件对话框,打开保存文件等,但以下函数均只是获取文件/文件夹路径和名称,并不执行打开、保存等实际操作 void MyWidget::on_pushButton_2_clicked(){ //该类有许多其他函数,可自行查阅 QString fileName = QFileDialog::getOpenFileName(this, "单文件选择框", "d:", "图片文件(*png *jpg);;文本文件(*txt)"); //以模态方式运行一个文件对话框,选择单个文件,不能是文件夹 //单击打开,返回所选文件名称格为如:fileName: "E:/爱佳利/Pictures/she/she.png" //多个文件是getOpenFileNames,需要使用QStringList fileNames = //4参数为父窗口,对话框标题,默认路径,文件类型过滤器,不指定则默认可选择所有类型的文件 //同类别两文件类型之间需要一个空格*png *jpg,不同类别之间两分号;; //另有getSaveFileName()保存文件和getExistingDirectory()获取文件夹路径,不能是文件 qDebug() << "fileName: " << fileName;/* QString fileName1 = QFileDialog::getSaveFileName(this, "保存文件对话框", "d:","图片类型(*png)"); qDebug() << "fileName1: " << fileName1 ; QString fileName2 = QFileDialog::getExistingDirectory(this, "文件路径对话框", "d:"); qDebug() << "fileName2: " << fileName2; QStringList fileNames = QFileDialog::getOpenFileNames(this, "多文件选择框", "d:", "图片文件(*png *jpg)"); qDebug() << "fileNames: "; for(auto x: fileNames){ qDebug() << x; }*/}选取字体的对话框 ...

September 8, 2019 · 2 min · jiezi

Qt设置程序图标

设置程序的图标需要一个.ico图标文件,步骤如下:1.将.ico文件复制到工程文件夹中,命名为shili.ico2.打开.pro文件,在末尾添加代码 RC_ICONS = shili.ico3.重新Run一下

September 7, 2019 · 1 min · jiezi

QtCharts之QValueAxis类

文章首发自公众号:: nullobject 。个人站点:https://www.nullobject.cn 这篇文章主要讲解QValueAxis类的API及其使用。0x00 关于QValueAxisQValueAxis,即数值轴,适用于具有连续数据坐标的图表。QValueAxis作为QAbstractAxis的实现类之一,在继承了QAbstractAxis特性的同时,根据数值轴的特点封装实现了许多方便实用的功能。QValueAxis使用起来也非常简单,在上一篇文章QAbstractAxis中的示例代码均是使用QValueAxis实例来说明的。本文主要介绍QValueAxis实现的功能。QValueAxis使用示例:#include <QApplication>#include <QChartView>#include <QLineSeries>#include <QValueAxis>#include <QDebug>QT_CHARTS_USE_NAMESPACEint main(int argc, char *argv[]){ QApplication a(argc, argv); // 创建QChartView对象 QChartView *chartView = new QChartView; chartView->setRenderHint(QPainter::Antialiasing); // 创建序列 QLineSeries *series = new QLineSeries(); // 隐藏图例 chartView->chart()->legend()->hide(); // 添加数据 series->append(0,2); series->append(QPointF(2,6)); series->append(3,8); series->append(7,9); series->append(11,3); *series << QPointF(11,2) << QPointF(15,5) << QPointF(18,4) << QPointF(19,2); // 添加序列到图表 chartView->chart()->addSeries(series); // 创建X轴 QValueAxis *axisX = new QValueAxis; // 设置QValueAxis属性 axisX->setRange(10, 20.5); axisX->setTickCount(5); axisX->setLabelFormat("%.2f"); chartView->chart()->setAxisX(axisX, series); // 创建Y轴 QValueAxis *axisY = new QValueAxis; axisY->setRange(0, 10); axisY->setTickCount(5); axisY->setLabelFormat("%.2f"); chartView->chart()->setAxisY(axisY, series); chartView->resize(400,300); chartView->show(); return a.exec();}效果:0x01 设置刻度线在Qt 5.12版本之前,QValueAxis只支持固定的刻度线设置,只能通过setTickCount设置刻度线的数量,刻度线会平均分布在坐标轴。而在Qt最新版本5.12版中,QValueAxis支持通过tickType属性来设置刻度线为固定分布(TicksFixed)或者是动态分布(TicksDynamic)。QValueAxis::TickType tickType:设置刻度类型QValueAxis::TickType tickType() const;void setTickType(QValueAxis::TickType type);其中TickType为QValueAxis中声明的用于描述刻度类型(刻度线和刻度标签在轴上的位置)的枚举类:enum TickType { TicksDynamic = 0, TicksFixed};tickType属性改变时触发tickTypeChanged(QValueAxis::TickType)信号TicksFixed 设置刻度位置为均匀分布QValueAxis默认的刻度类型为TicksFixed。将刻度类型设置为TicksFixed,可以通过设置tickCount属性值来指定刻度线的数量,此时刻度线会被均匀地地分布在坐标轴上。默认的刻度线数量是5条,最低数量不能低于2。:axisY->setRange(0, 10);axisY->setTickType(QValueAxis::TickType::TicksFixed);axisY->setTickCount(6);效果:其中tickCount的操作函数声明如下:int tickCount() const;void setTickCount(int count);tickCount属性修改只在tickType值为TicksFixed时有效。tickCount属性改变时触发tickCountChanged(int)信号。TicksDynamic 设置刻度位置为动态分布动态设置刻度的位置,需要通过设置锚点tickAnchor和刻度间距tickInterval属性值来实现,必须要设置指定tickInterval才有效果:axisY->setRange(0, 10);axisY->setTickType(QValueAxis::TickType::TicksDynamic);// 设置刻度间距为3axisY->setTickInterval(3);// 设置锚点坐标为5axisY->setTickAnchor(5);效果:其中锚点tickAnchor属性用于指定刻度线和标签开始绘制的位置,刻度间距tickInterval属性用于指定刻度与刻度之间的距离。上示例子中将tickAnchor和tickInterval分别设置为5和3,表示刻度将从坐标为5的位置开始,向轴两端分布,如果不显示设置tickAnchor,则默认从坐标轴的起始位置开始分布;tickInterval的类型为qreal类型,支持设置刻度间隔为小数。修改tickAnchor和tickInterval对应会触发的信号分别为:tickAnchorChanged(int)和tickIntervalChanged(qreal)。0x02 设置坐标轴显示范围QValueAxis通过max和min两个属性来表示坐标轴的最大和最小值,可以通过调用对应的方法来设置坐标轴的显示范围。qreal max:设置坐标轴最大值qreal max() const;void setMax(qreal max);max属性修改会触发maxChanged(qreal)信号。qreal min:设置坐标轴最小值qreal min() const;void setMin(qreal min);min属性修改会触发minChanged(qreal)信号。setRange:设置坐标轴显示范围void setRange(qreal min, qreal max);除了可以调用setMax或setMin单独设置坐标轴的极值外,也可以直接调用setRange同时设置坐标轴的最大、最小值:// axisY->setMin(0);// axisY->setMax(10);// 等价于setRange(0,10);axisY->setRange(0, 10);当坐标轴的最大值max或者最小值min发生改变时,都会触发rangeChanged(qreal min,qreal max)信号。0x03 设置刻度标签显示格式QValueAxis坐标轴支持通过labelFormat属性设置标签的显示格式,例如指定显示小数位数等。QString labelFormat:设置标签格式QString labelFormat() const;void setLabelFormat(const QString &format);其中传参format为需要指定的字符串格式,例如设置为显示小数点后两位数:axisX->setLabelFormat("%.2f");目前labelFormat支持设置以下转换说明符、长度修饰符以及标准C++库中printf()函数提供的格式标志:d, i, o, x, X, f, F, e, E, g, G, c。具体使用可以百度搜索了解:printf() 输出格式。修改该属性会触发labelFormatChanged(const QString&)信号。0x04 The End :) ...

April 3, 2019 · 1 min · jiezi

QtCharts之QAbstractAxis类

文章首发自公众号:: nullobject 。个人站点:https://www.nullobject.cn这篇文章主要讲解QAbstractAxis类的API及其使用0x00 QtCharts中坐标轴结构在学习QAbstractAxis类之前,需要先熟悉QtCharts中轴的组成元素都有哪些:QtCharts中,一个坐标轴的内容大致包含以下几种:轴标题(title)、轴刻度标签(labels)、轴线(lines)、网格线(grid lines)、和轴阴影(shades)。通过QAbstractAxis可以分别对以上几种元素进行单独控制。0x01 设置标题QAbstractAxis可以设置坐标轴标题的显示/隐藏、颜色、内容和字体等几个属性。示例例如,设置坐标轴标题内容为axisTitle,颜色为蓝色,字体15号加粗,并显示出来:// 显示标题 axisXLeft->setTitleVisible(true); // 设置标题内容 axisXLeft->setTitleText(QStringLiteral(“I am axis’s title”));// 设置颜色 axisXLeft->setTitleBrush(QBrush(Qt::blue)); // 设置字体12号加粗 QFont font = axisXLeft->titleFont(); font.setPointSize(15); font.setBold(true); axisXLeft->setTitleFont(font); 结果:titleVisible:设置标题显示bool isTitleVisible() const;void setTitleVisible(bool visible = true);坐标轴标题默认情况下是显示的。修改该属性时会触发titleVisibleChanged(bool visible)信号。titleText:设置标题内容QString titleText() const;void setTitleText(const QString &title);默认情况下,QAbstractAxis不会设置任何标题内容。用户可以根据需要修改坐标轴标题。标题发生改变时会触发titleTextChanged(const QString &text)信号。titleFont:设置标题字体QFont titleFont() const;void setTitleFont(const QFont &font);该属性通过QFont来设置标题的字体风格。该属性发生改变时,会触发titleFontChanged(const QFont &font)信号。titleBrush:设置标题颜色画刷QBrush titleBrush() const;void setTitleBrush(const QBrush &brush);注意目前只支持通过画刷来设置颜色,不支持设置画刷得其他效果(如画刷风格BrushStyle等)。该属性发生改变会触发titleBrushChanged(const QBrush &brush)信号。0x02 设置刻度标签QAbstractAxis除了可以设置坐标轴刻度标签的显示/隐藏、颜色、和字体几个属性外,还可设置刻度标签的倾斜角度。示例例如,设置轴刻度标签显示,倾斜-45度,红色,加粗9号字体:// 显示刻度标签 axisXLeft->setLabelsVisible(true); // 倾斜45度 axisXLeft->setLabelsAngle(-45); // 颜色 axisXLeft->setLabelsColor(Qt::red); // 加粗9号 font = axisXLeft->labelsFont(); font.setBold(true); font.setPointSize(9); axisXLeft->setLabelsFont(font); 效果:labelsAngle:设置倾斜角度int labelsAngle() const;void setLabelsAngle(int angle);设置刻度标签的倾斜角度,默认为水平显示。该属性发生改变时,触发labelsAngleChanged(int angle)信号。labelsColor、labelsBrush:设置颜色QColor labelsColor() const;void setLabelsColor(QColor color);QBrush labelsBrush() const;void setLabelsBrush(const QBrush &brush);轴刻度标签的颜色可以通过labelsColor者labelsBrush任一属性设置来实现。两者的区别在于被修改时触发的信号不一样、修改labelsColor属性稍微便利些而已,且通过修改labelsBrush实现时也只支持修改QBrush颜色,而不支持QBrush的其它属性设置。实际上修改轴刻度标签颜色,内部都是通过设置QBrush来实现。修改labelsColor属性会触发labelsColorChanged(QColor color)信号;修改labelsBrush属性会触发labelBrushChanged(const QBrush &brush)信号。labelsFont:设置字体风格QFont labelsFont() const;void setLabelsFont(const QFont &font);使用方式与修改轴标题字体相同。该属性发生改变会触发labelsFontChanged(const QFont &font)信号。labelsVisible:设置显示/隐藏刻度标签bool labelsVisible() const;void setLabelsVisible(bool visible = true);默认为显示刻度标签。该属性修改时触发labelsVisibleChanged(bool visible)信号:0x03 设置轴线可以设置轴线显示/隐藏、轴线画笔、方向倒置。示例例如显示轴线,并为其设置颜色为红色、宽度为2的画笔:// 显示轴线axisXLeft->setLineVisible(true); // 设置轴线画笔QPen pen = axisXLeft->linePen(); pen.setColor(Qt::red); pen.setWidth(2); axisXLeft->setLinePen(pen);效果:lineVisible:设置显示轴线bool isLineVisible() const;void setLineVisible(bool visible = true);默认会显示轴线。该属性发生改变时会触发lineVisibleChanged(bool visible)信号。linePen:设置轴线画笔QPen linePen() const;void setLinePen(const QPen &pen);通过设置轴线画笔,可以自定义轴线宽度、绘制颜色等。如果只需要修改轴线颜色,可以直接调用setLinePenClolor(QColor color)方法。改属性发生改变时会触发linePenChanged(const QPen &pen)信号。通过setLinePenColor修改轴线颜色时会触发gridLineColorChanged(const QColor &color)信号。reverse:翻转坐标轴bool isReverse() const;void setReverse(bool reverse = true);将坐标轴的极值方向翻转,左侧为默认reverse=false,右侧为翻转之后的效果:注意:该属性仅在使用笛卡尔坐标系的图表上有效,比如折线、曲线、散点图和使用笛卡尔坐标系的面积图。reverse值改变时会触发reverseChanged(bool)信号。0x04 设置网格线QtCharts的坐标轴网格线分为主网格线gridLine和次网格线minorGridLine,主网格线相当于刻度线的延申(例如在QValueAxis),次网格线分布在相邻的两条主网格线之间,且次网格线需要由QAbstractAxis的子类,即具体类型的坐标轴实现才能支持。示例:以QValueAxis为例,显示主次网格线并设置颜色:// 设置网格线/刻度数量axisXLeft->setTickCount(5);axisXLeft->setMinorTickCount(5);// 主网格线axisXLeft->setGridLineVisible(true);axisXLeft->setGridLineColor(Qt::darkGray);// 次网格线axisXLeft->setMinorGridLineVisible(true);axisXLeft->setMinorGridLineColor(Qt::gray);效果:gridVisible、minorGridVisible设置显示网格线// 获取/设置显示主网格线,默认显示bool isGridLineVisible() const;void setGridLineVisible(bool visible = true);// 获取/设置显示次网格线,默认不显示bool isMinorGridLineVisible() const;void setMinorGridLineVisible(bool visible = true);gridVisible改变时触发gridVisibleChanged(bool visible)信号。minorGridVisible改变时触发minorGridVisibleChanged(bool visible)信号。gridLinePen、minorGridLinePen设置网格线画笔// 设置主网格线画笔QPen gridLinePen() const;void setGridLinePen(const QPen &pen);// 设置次网格线画笔QPen minorGridLinePen() const;void setMinorGridLinePen(const QPen &pen);与轴线颜色的设置类似,如果只需要修改网格线的颜色,可以直接调用对应的setGridLineColor(const QColor &color)或者setMinorGridLineColor(const QColor &color)方法快速设置。gridLinePen改变时触发gridLinePenChanged(const QPen &pen)信号。minorGridLinePen改变时触发minorGridLinePenChanged(const QPen &pen)信号。gridLineColor改变时触发gridLineColorChanged(const QPen &pen)信号。minorGridLineColor改变时触发minorGridLineColorChanged(const QPen &pen)信号。0x05 设置阴影QtCharts坐标轴阴影指的是相邻主网格线之间的区域。QAbstractAxis中提供了对阴影边框(shadesBorder)、阴影区域(shadesArea)的设置:示例以QValueAxis为例,设置坐标轴的阴影边框和填充:// 显示阴影区域,包括阴影边框axisXLeft->setShadesVisible(true);// 设置阴影边框QPen sPen = axisXLeft->shadesPen();sPen.setWidth(5);sPen.setColor(Qt::yellow);axisXLeft->setShadesPen(sPen);//axisXLeft->setShadesBorderColor(Qt::darkYellow);// 设置阴影区域颜色填充axisXLeft->setShadesBrush(QBrush(QColor(48,157,255,125)));//axisXLeft->setShadesColor(Qt::blue);效果:shadesBorderColor、shadesPen设置阴影边框QColor shadesBorderColor() const;void setShadesBorderColor(QColor color);QPen shadesPen() const;void setShadesPen(const QPen &pen);设置阴影边框,如果只需要改变颜色可以直接调用setShadesBorderColor(QColor),需要设置更多属性可以调用setShadesPen(const QPen&)为阴影边框设置一个画笔对象。shadesBorderColor属性改变会触发shadesBorderColorChanged(QColor color)信号。shadesPen属性改变会触发shadesPenChanged(const QPen &pen)信号。shadesBrush、shadesColor设置阴影区域填充QBrush shadesBrush() const;void setShadesBrush(const QBrush &brush);QColor shadesColor() const;void setShadesColor(QColor color);设置阴影区域填充,如果只需要修改颜色可以直接使用setShadesColor(QColor),需要设置更多效果可以调用setShadesBrush(const QBrush&)为阴影区域设置一个画刷,例如,设置画刷的填充风格为DiagCrossPattern:QBrush sBrush = axisXLeft->shadesBrush();sBrush.setColor(QColor(48,157,255,125));// 设置画刷风格sBrush.setStyle(Qt::BrushStyle::DiagCrossPattern);axisXLeft->setShadesBrush(sBrush);效果:shadesBrush值修改会触发shadesBrushChanged(const QBrush &brush)信号。shadesColor值修改会触发shadesColorChanged(QColor color)信号。0x06 The End :) ...

April 2, 2019 · 2 min · jiezi

QtCharts之QXYSeries

文章首发自公众号:: nullobject 。个人站点:https://www.nullobject.cn这篇文章主要介绍QXYSeries类的API及其使用0x00 前言QXYSeries作为QAbstractSeries的派生类之一,主要负责实现以二维点集为数据源,坐标类型为二维坐标系的图表类型,包括折线图、曲线图和散点图等。QXYSeries封装了大量对数据源进行增删改操作的函数和信号,同时内部实现了控制数据点在坐标系上的显示形态(点标签的格式、颜色、是否显示等)的功能。0x01 显示和控制点标签Qt图表中的点标签指的是数据点在图表上对应位置的附加信息显示(比如点的坐标或者其他信息):QXYSeries类中提供了pointLabels*开头的五个属性及对应的方法和信号来操作点标签的显示风格。pointLabelsClipping : 获取和设置是否对点标签超出绘图区域边缘的部分进行裁剪:bool pointLabelsClipping() const;void setPointLabelsClipping(bool enabled = true);效果:可以看到,当设置pointLabelsClipping属性为true(默认值)时,点标签超出绘图区域的部分会被裁剪掉。pointLabelsClipping属性发生改变时,会触发pointLabelsClippingChanged(bool clipping)信号。pointLabelsColor : 获取和设置点标签的显示颜色:QColor pointLabelsColor() const;void setPointLabelsColor(const QColor &color);效果:上图分别为将pointLabelsColor属性设置为黑色和绿色的效果。看到这您有可能会有疑问:咦怎么只改变了坐标的颜色,而折线上点的颜色没有变?注意了,这里的点标签是指图表上对数据点加以说明的信息部分,不包括点本身的显示。pointLabelsColor属性发生改变时,会触发pointLabelsColorChanged(const QColor &color)信号。pointLabelsFont : 获取和设置点标签的显示字体:QFont pointLabelsFont() const;void setPointLabelsFont(const QFont &font);该属性通过一个QFont设置来实现:// 获取pointLabels默认字体QFont font = series->pointLabelsFont();// 加粗font.setBold(true);// 斜体font.setItalic(true);// 设置字体大小font.setPointSize(12);// 设置字体为Arial类型font.setFamily(QStringLiteral(“Arial”));// 更新pointLabels字体series->setPointLabelsFont(font);效果:pointLabelsFont属性发生改变时,会触发pointLabelsFontChanged(const QFont &font)信号。pointLabelsFormat : 获取和设置点标签的显示格式:QString pointLabelsFormat() const;void setPointLabelsFormat(const QString &format);QXYSeries类提供了两个占位符来设置点标签显示真实坐标数据:@xPointX轴坐标@yPointY轴坐标例如,我们需要以:(15,23)这样的格式来显示点标签,可以这样设置,即可实现上文中点标签的显示格式效果:// 设置点标签格式series->setPointLabelsFormat(QStringLiteral("(@xPoint,@yPoint)"));pointLabelFormat属性默认被设置为没有括号的坐标格式:@xPoint, @yPoint。pointLabelsFormat属性发生改变时,会触发pointLabelsFormatChanged(const QString &format)信号。pointLabelsVisible : 获取和设置显示/隐藏点标签:bool pointLabelsVisible() const;void setPointLabelsVisible(bool visible=true);该属性默认被设置为false。// 隐藏点标签series->setPointLabelsVisible(false);效果:pointLabelsVisible属性发生改变时,会触发pointLabelsVisibilityChanged(bool visible)信号。pointsVisible : 获取和设置显示/隐藏点在图表上的标注:bool pointsVisible() const;void setPointsVisible(bool visible=true);与pointsLabelVisible不同,pointsLabelVisible设置的是点标签的显示,而pointsVisible设置的是点本身在图表上的位置标注。该属性默认被设置为false。对比显示和隐藏点标注效果:0x02 对数据源进行增删改QXYSeries类中封装了一系列的重载方法用于操作图表的数据源进行增删改。QXYSeries内部用一个模板类型为QPointF的QVector来持有数据源,其声明在qxyseries_p.h头文件内:增加数据可以调用append的对应重载方法,或者是重载操作符<<添加单个点或者整个点集到数据源的尾部:void append(qreal x, qreal y);void append(const QPointF &point);void append(const QList<QPointF> &points);QXYSeries& operator<<(const QPointF &point);QXYSeries& operator<<(const QList<QPointF> &points);也可以调用insert方法将数据点插入到数据源的指定位置:void insert(int index, const QPointF &point);对应地,不管以何种方式,成功添加数据后都会触发pointAdded(int index)信号,index为被添加的数据的下标。需要注意:每添加一个点就会触发一次pointAdded信号,即批量添加数据时会触发对应次数的pointAdded。删除数据QXYSeries提供了remove重载方法和removePoints方法来移除目标数据:// 删除指定坐标的点void remove(qreal x, qreal y);void remove(const QPointF &point);// 删除指定索引下标的点void remove(int index);// 从下标index位置开始,删除count数量的点void removePoints(int index, int count);与增加数据类似,成功删除数据后会触发对应次数的pointRemoved(int index)信号,index为被删除的数据的下标。修改数据源修改数据源通过replace系列的重载方法实现:// 替换具体坐标的点void replace(qreal oldX, qreal oldY, qreal newX, qreal newY);void replace(const QPointF &oldPoint, const QPointF &newPoint);// 替换指定索引下标的点void replace(int index, qreal newX, qreal newY);void replace(int index, const QPointF &newPoint);// 替换整个数据源void replace(QList<QPointF> points);void replace(QVector<QPointF> points);当只替换数据源的局部数据点(调用前四种重载方法)时,会触发pointReplaced(int index)信号,index为被替换的点的下标;而当替换了整个数据源数据(调用后两种方法)时,则会触发pointsReplaced()信号。需要注意:调用replace后两种重载替换整个数据源时,传QList还是传QVector在性能上是有所区别的:直接传入QList结构的数据集远远比逐个点替换或者先清除所有点再添加这两种方式的效率要高。而直接传入QVector结构的数据集又比前者效率要高。因此:需要批量更新数据点时,应当优先选择void replace(QVector<QPointF> points);这个重载方法。究其原因:本小节一开始就介绍了,QXYSeries内部持有数据源的数据结构为QVector<QPointF>,而参数为QList<QPointF>的重载方法的内部实现也是将QList转换为QVector,再调用参数为QVector<QPointF> 的重载方法实现对数据的更新,无形中多了一个数据转换的步骤,拉低性能:Tips:QList和QVector两个容器本身的效率上也是有区别的,Qt官方推荐优先使用QVector。详细可以参考QVector的官方文档介绍。获取数据源QXYseries提供了返回类型分别为QList<QPointF>和QVector<QPointF>的方法获取数据源:QList<QPointF> points() const;QVector<QPointF> pointsVector() const;与更新replace方法批量更新数据源的重载类似,points()方法获取数据源的方法,内部实现也是获取原始数据源再将其转为QList类型返回;pointsVector()方法则直接返回原始的QVector数据源。0x03 QXYSeries中的鼠标操作QXYSeries共提供了五个鼠标事件响应信号,分别是:单击clicked、双击doubleClicked、鼠标键按下pressed,鼠标键松开released、光标移到图表线上或从图表移开hovered:series->connect(series,&QLineSeries::clicked,[](const QPointF& point){ qDebug() << “point clicked:” << point;});series->connect(series,&QLineSeries::doubleClicked,[](const QPointF& point){ qDebug() << “point double clicked:” << point;});series->connect(series,&QLineSeries::hovered,[](const QPointF& point,bool state){ qDebug() << “point hovered:” << point << " state:" << (state?“光标移动到图表上”:“光标从图表上移开”);});series->connect(series,&QLineSeries::pressed,[](const QPointF& point){ qDebug() << “point pressed:” << point;});series->connect(series,&QLineSeries::released,[](const QPointF& point){ qDebug() << “point released:” << point;});运行程序,执行光标移动到图表序列上->左键双击->光标从图表序列上方移开,结果如下:point hovered: QPointF(4.58291,8.71473) state: moved to seriespoint pressed: QPointF(4.58291,8.71473)point released: QPointF(4.58291,8.71473)point clicked: QPointF(4.58291,8.71473)point double clicked: QPointF(4.58291,8.71473)point pressed: QPointF(4.58291,8.71473)point released: QPointF(4.58291,8.71473)point clicked: QPointF(4.58291,8.71473)point hovered: QPointF(4.71022,8.18182) state: moved from series0x04 The End. ...

March 30, 2019 · 2 min · jiezi

Qt Charts之QAbstractSeries类

这篇文章主要讲解QAbstractSeries的API及其使用。0x00 写在前面:Qt Charts的组成结构 理解本文章内容之前,需要读者对Qt Charts的基本组成有个整体认识,具体可以参考这篇文章:Qt Charts 基本组成。Qt Charts主要由QChartView、QChart、QLegend图例、坐标轴(由QAbstractAxis子类实现)、数据源(由QAbstractSeries子类实现)等组成:0x01 QAbstractSeries类 由上图可知,Qt Charts图表中,数据的最终呈现主要由QAbstractSeries及其派生类负责(上图为QLineSeries),通常在实际开发中都是直接使用QAbstractSeries的派生类来实现功能。QAbstractSeries作为Qt Charts模块中所有数据序列类(Q*Series)的基类,与其子类的继承关系大致如下:Tips:由于QAbstractSeries的子类及其子类的子类数目众多,这里只大致列出了从QAbstractSeries<–QXYSeries<–QLineSeries的继承关系,详情可以参考上文提到的文章链接以及Qt官方文档。可以看到,以QLineSeries为例,QLineSeries继承自QXYSeries,而QXYSeries正是继承自QAbstractSeries类,同时通过学习QLineSeries相关文档和源码了解到,QLineSeries的功能实现几乎都继承于其父类QXYSeries和QAbstractSeries类,因此。要想熟练使用QLineSeries,实现美丽的折线图,学习理解QXYSeries和QAbstractSeries类的API是必须的,本文主要介绍QAbstractSeries。0x02 QAbstractSeries属性QString name;获取和设置series名称,即QAbstractSeries所表示的图形图例名称,支持HTML格式的文本。QString name() const;获取series图例名称。void setName(const QString &name);设置series图例名称。当图例名称发生改变时,会触发QAbstractSeries的nameChanged()信号。bool useOpenGL;获取和设置series是否开启OpenGL加速。bool useOpenGL() const;获取是否开启OpenGL加速。void setUseOpenGL(bool enable=true);设置开启/关闭OpenGL加速渲染,默认关闭。该选项发生改变时会触发QAbstractSeries的useOpenGLChanged()信号。Tips : 在不开启OpenGL加速就能满足性能要求且对该选项带来的副作用不熟悉的情况下,建议不要开启OpenGL加速!当需要绘制大数据量的图表序列时,开启OpenGL加速之后series的绘制性能显著提升。但是Qt Charts实现的OpenGL加速(依托QOpenGLWidget组件实现)迄今为止仍存在一些问题,比如MDI程序环境下,开启了OpenGL加速的图表序列会被置顶于所有MDI子窗口之上,造成图表重叠错乱的问题:而且,目前只有QLineSeries和QScatterSeries两种类型的图表支持开启OpenGL绘制,且当QLineSeries作为面积图QAreaSeries的边缘线时也不能开启OpenGL。因此,慎重开启此选项!qreal opacity;获取和设置图表序列显示的透明度。qreal opacity() const;获取series当前设置的透明度。void setOpacity(qreal opacity);设置series显示的透明度,设置范围:全透明0.0~1.0不透明,该属性值发生改变时会触发opacityChanged()信号。bool visible;获取和设置是否显示当前图表。bool isVisible() const;获取是否显示当前图表;void setVisible(bool visible = true);设置是否显示当前图表,该属性值发生改变时会触发visibleChanged()信号。const SeriesType type;该属性代表当前图表序列series的类型,QAbstractSeries中声明了一个纯虚函数用于操作该属性:virtual QAbstractSeries::SeriesType type() const = 0;QAbstractSeries的子类需要手动实现该函数并返回对应的图表类型。SeriesType是一个枚举类,描述了Qt Charts当前支持的图表类型:0x03 QAbstractSeries公有方法QAbstractSeries主要的公有方法有:bool QAbstractSeries::attachAxis(QAbstractAxis *axis);附加坐标轴到图表序列series,附加成功时返回true,否则返回false: // 创建横、纵坐标轴 QValueAxis *axisX = new QValueAxis; QValueAxis *axisY = new QValueAxis; // 设置坐标轴颜色 axisX->setLinePen(QPen(Qt::blue)); axisY->setLinePen(QPen(Qt::blue)); // 设置坐标轴刻度线颜色和宽度 QPen pen(Qt::black); pen.setWidth(1); axisX->setGridLinePen(pen); axisY->setGridLinePen(pen); // 添加坐标轴到QChart组件 chart->addAxis(axisX,Qt::AlignBottom); chart->addAxis(axisY,Qt::AlignLeft); // 设置显示刻度范围 axisX->setRange(0,25); axisY->setRange(0,15); // 附加坐标系到图表序列series series->attachAxis(axisX); series->attachAxis(axisY); 效果:当同一方向上有多个坐标轴同时依附到同一个图表序列上时,这些坐标轴将会被设置为相同的刻度范围,且经过实践证明,自动调整后的刻度范围是最后被依附到图标序列的坐标轴刻度范围: //增加第二条个横纵坐标系 QValueAxis *axisX1 = new QValueAxis; QValueAxis *axisY1 = new QValueAxis; axisX1->setRange(-5,15); axisY1->setRange(0,5); chart->addAxis(axisX1,Qt::AlignBottom); chart->addAxis(axisY1,Qt::AlignLeft); //将两个坐标系依附到图标序列series series->attachAxis(axisX1); series->attachAxis(axisY1); 效果:QList<QAbstractAxis *> QAbstractSeries::attachedAxes();获取图表序列当前依附的所有坐标轴集合: // 打印上一步中依附到series的所有坐标轴集合 qDebug() << “attached axes:” << series->attachedAxes(); 结果:QChart *QAbstractSeries::chart() const;获取当前图表序列series所属的QChart组件。通过QChart::addSeries()方法将series添加到QChart组件后可以通过此方法获取series被添加到的QChart对象指针。bool QAbstractSeries::detachAxis(QAbstractAxis *axis);从当前图表序列分离坐标轴。0x04 The End. ...

March 27, 2019 · 1 min · jiezi

pyqt5——菜单和工具栏

菜单和工具栏这个章节,我们会创建状态栏、菜单和工具栏。菜单是一组位于菜单栏的命令。工具栏是应用的一些常用工具按钮。状态栏显示一些状态信息,通常在应用的底部。主窗口QMainWindow提供了主窗口的功能,使用它能创建一些简单的状态栏、工具栏和菜单栏。主窗口是下面这些窗口的合称,所以教程在最下方。状态栏状态栏是用来显示应用的状态信息的组件。#!/usr/bin/python3# -- coding: utf-8 --“““ZetCode PyQt5 tutorial This program creates a statusbar.Author: Jan BodnarWebsite: zetcode.com Last edited: August 2017"““import sysfrom PyQt5.QtWidgets import QMainWindow, QApplicationclass Example(QMainWindow): def init(self): super().init() self.initUI() def initUI(self): self.statusBar().showMessage(‘Ready’) self.setGeometry(300, 300, 250, 150) self.setWindowTitle(‘Statusbar’) self.show()if name == ‘main’: app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_())状态栏是由QMainWindow创建的。self.statusBar().showMessage(‘Ready’)调用QtGui.QMainWindow类的statusBar()方法,创建状态栏。第一次调用创建一个状态栏,返回一个状态栏对象。showMessage()方法在状态栏上显示一条信息。程序预览:菜单栏菜单栏是非常常用的。是一组命令的集合(Mac OS下状态栏的显示不一样,为了得到最相似的外观,我们增加了一句menubar.setNativeMenuBar(False))。#!/usr/bin/python3# -- coding: utf-8 --“““ZetCode PyQt5 tutorial This program creates a menubar. Themenubar has one menu with an exit action.Author: Jan BodnarWebsite: zetcode.com Last edited: January 2017"““import sysfrom PyQt5.QtWidgets import QMainWindow, QAction, qApp, QApplicationfrom PyQt5.QtGui import QIconclass Example(QMainWindow): def init(self): super().init() self.initUI() def initUI(self): exitAct = QAction(QIcon(’exit.png’), ‘&Exit’, self) exitAct.setShortcut(‘Ctrl+Q’) exitAct.setStatusTip(‘Exit application’) exitAct.triggered.connect(qApp.quit) self.statusBar() menubar = self.menuBar() fileMenu = menubar.addMenu(’&File’) fileMenu.addAction(exitAct) self.setGeometry(300, 300, 300, 200) self.setWindowTitle(‘Simple menu’) self.show() if name == ‘main’: app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_())我们创建了只有一个命令的菜单栏,这个命令就是终止应用。同时也创建了一个状态栏。而且还能使用快捷键Ctrl+Q退出应用。exitAct = QAction(QIcon(’exit.png’), ‘&Exit’, self) exitAct.setShortcut(‘Ctrl+Q’)exitAct.setStatusTip(‘Exit application’)QAction是菜单栏、工具栏或者快捷键的动作的组合。前面两行,我们创建了一个图标、一个exit的标签和一个快捷键组合,都执行了一个动作。第三行,创建了一个状态栏,当鼠标悬停在菜单栏的时候,能显示当前状态。exitAct.triggered.connect(qApp.quit)当执行这个指定的动作时,就触发了一个事件。这个事件跟QApplication的quit()行为相关联,所以这个动作就能终止这个应用。menubar = self.menuBar()fileMenu = menubar.addMenu(’&File’)fileMenu.addAction(exitAct)menuBar()创建菜单栏。这里创建了一个菜单栏,并在上面添加了一个file菜单,并关联了点击退出应用的事件。程序预览:子菜单子菜单是嵌套在菜单里面的二级或者三级等的菜单。#!/usr/bin/python3# -- coding: utf-8 --“““ZetCode PyQt5 tutorial This program creates a submenu.Author: Jan BodnarWebsite: zetcode.com Last edited: August 2017"““import sysfrom PyQt5.QtWidgets import QMainWindow, QAction, QMenu, QApplicationclass Example(QMainWindow): def init(self): super().init() self.initUI() def initUI(self): menubar = self.menuBar() fileMenu = menubar.addMenu(‘File’) impMenu = QMenu(‘Import’, self) impAct = QAction(‘Import mail’, self) impMenu.addAction(impAct) newAct = QAction(‘New’, self) fileMenu.addAction(newAct) fileMenu.addMenu(impMenu) self.setGeometry(300, 300, 300, 200) self.setWindowTitle(‘Submenu’) self.show() if name == ‘main’: app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_())这个例子里,有两个子菜单,一个在file菜单下面,一个在file的import下面。impMenu = QMenu(‘Import’, self)使用QMenu创建一个新菜单。impAct = QAction(‘Import mail’, self) impMenu.addAction(impAct)使用addAction添加一个动作。程序预览:勾选菜单下面是一个能勾选菜单的例子#!/usr/bin/python3# -- coding: utf-8 --“““ZetCode PyQt5 tutorial This program creates a checkable menu.Author: Jan BodnarWebsite: zetcode.com Last edited: August 2017"““import sysfrom PyQt5.QtWidgets import QMainWindow, QAction, QApplicationclass Example(QMainWindow): def init(self): super().init() self.initUI() def initUI(self): self.statusbar = self.statusBar() self.statusbar.showMessage(‘Ready’) menubar = self.menuBar() viewMenu = menubar.addMenu(‘View’) viewStatAct = QAction(‘View statusbar’, self, checkable=True) viewStatAct.setStatusTip(‘View statusbar’) viewStatAct.setChecked(True) viewStatAct.triggered.connect(self.toggleMenu) viewMenu.addAction(viewStatAct) self.setGeometry(300, 300, 300, 200) self.setWindowTitle(‘Check menu’) self.show() def toggleMenu(self, state): if state: self.statusbar.show() else: self.statusbar.hide() if name == ‘main’: app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_())本例创建了一个行为菜单。这个行为/动作能切换状态栏显示或者隐藏。viewStatAct = QAction(‘View statusbar’, self, checkable=True)用checkable选项创建一个能选中的菜单。viewStatAct.setChecked(True)默认设置为选中状态。def toggleMenu(self, state): if state: self.statusbar.show() else: self.statusbar.hide()依据选中状态切换状态栏的显示与否。程序预览:右键菜单右键菜单也叫弹出框(!?),是在某些场合下显示的一组命令。例如,Opera浏览器里,网页上的右键菜单里会有刷新,返回或者查看页面源代码。如果在工具栏上右键,会得到一个不同的用来管理工具栏的菜单。#!/usr/bin/python3# -- coding: utf-8 --“““ZetCode PyQt5 tutorial This program creates a context menu.Author: Jan BodnarWebsite: zetcode.com Last edited: August 2017"““import sysfrom PyQt5.QtWidgets import QMainWindow, qApp, QMenu, QApplicationclass Example(QMainWindow): def init(self): super().init() self.initUI() def initUI(self): self.setGeometry(300, 300, 300, 200) self.setWindowTitle(‘Context menu’) self.show() def contextMenuEvent(self, event): cmenu = QMenu(self) newAct = cmenu.addAction(“New”) opnAct = cmenu.addAction(“Open”) quitAct = cmenu.addAction(“Quit”) action = cmenu.exec_(self.mapToGlobal(event.pos())) if action == quitAct: qApp.quit() if name == ‘main’: app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_())还是使用contextMenuEvent()方法实现这个菜单。action = cmenu.exec_(self.mapToGlobal(event.pos()))使用exec_()方法显示菜单。从鼠标右键事件对象中获得当前坐标。mapToGlobal()方法把当前组件的相对坐标转换为窗口(window)的绝对坐标。if action == quitAct: qApp.quit()如果右键菜单里触发了事件,也就触发了退出事件,执行关闭菜单行为。程序预览:工具栏菜单栏包含了所有的命令,工具栏就是常用的命令的集合。#!/usr/bin/python3# -- coding: utf-8 --“““ZetCode PyQt5 tutorial This program creates a toolbar.The toolbar has one action, whichterminates the application, if triggered.Author: Jan BodnarWebsite: zetcode.com Last edited: August 2017"““import sysfrom PyQt5.QtWidgets import QMainWindow, QAction, qApp, QApplicationfrom PyQt5.QtGui import QIconclass Example(QMainWindow): def init(self): super().init() self.initUI() def initUI(self): exitAct = QAction(QIcon(’exit24.png’), ‘Exit’, self) exitAct.setShortcut(‘Ctrl+Q’) exitAct.triggered.connect(qApp.quit) self.toolbar = self.addToolBar(‘Exit’) self.toolbar.addAction(exitAct) self.setGeometry(300, 300, 300, 200) self.setWindowTitle(‘Toolbar’) self.show() if name == ‘main’: app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_())上面的例子中,我们创建了一个工具栏。这个工具栏只有一个退出应用的动作。exitAct = QAction(QIcon(’exit24.png’), ‘Exit’, self)exitAct.setShortcut(‘Ctrl+Q’)exitAct.triggered.connect(qApp.quit)和上面的菜单栏差不多,这里使用了一个行为对象,这个对象绑定了一个标签,一个图标和一个快捷键。这些行为被触发的时候,会调用QtGui.QMainWindow的quit方法退出应用。self.toolbar = self.addToolBar(‘Exit’)self.toolbar.addAction(exitAct)把工具栏展示出来。程序预览:主窗口主窗口就是上面三种栏目的总称,现在我们把上面的三种栏在一个应用里展示出来。首先要自己弄个小图标,命名为exit24.png#!/usr/bin/python3# -- coding: utf-8 --“““ZetCode PyQt5 tutorial This program creates a skeleton ofa classic GUI application with a menubar,toolbar, statusbar, and a central widget. Author: Jan BodnarWebsite: zetcode.com Last edited: August 2017学习交流:923414804"““import sysfrom PyQt5.QtWidgets import QMainWindow, QTextEdit, QAction, QApplicationfrom PyQt5.QtGui import QIconclass Example(QMainWindow): def init(self): super().init() self.initUI() def initUI(self): textEdit = QTextEdit() self.setCentralWidget(textEdit) exitAct = QAction(QIcon(’exit24.png’), ‘Exit’, self) exitAct.setShortcut(‘Ctrl+Q’) exitAct.setStatusTip(‘Exit application’) exitAct.triggered.connect(self.close) self.statusBar() menubar = self.menuBar() fileMenu = menubar.addMenu(’&File’) fileMenu.addAction(exitAct) toolbar = self.addToolBar(‘Exit’) toolbar.addAction(exitAct) self.setGeometry(300, 300, 350, 250) self.setWindowTitle(‘Main window’) self.show() if name == ‘main’: app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_())上面的代码创建了一个很经典的菜单框架,有右键菜单,工具栏和状态栏。textEdit = QTextEdit()self.setCentralWidget(textEdit)这里创建了一个文本编辑区域,并把它放在QMainWindow的中间区域。这个组件或占满所有剩余的区域。程序预览: ...

January 11, 2019 · 3 min · jiezi

俄罗斯方块游戏——pyqt5

本章我们要制作一个俄罗斯方块游戏。Tetris译注:称呼:方块是由四个小方格组成的俄罗斯方块游戏是世界上最流行的游戏之一。是由一名叫Alexey Pajitnov的俄罗斯程序员在1985年制作的,从那时起,这个游戏就风靡了各个游戏平台。俄罗斯方块归类为下落块迷宫游戏。游戏有7个基本形状:S、Z、T、L、反向L、直线、方块,每个形状都由4个方块组成,方块最终都会落到屏幕底部。所以玩家通过控制形状的左右位置和旋转,让每个形状都以合适的位置落下,如果有一行全部被方块填充,这行就会消失,并且得分。游戏结束的条件是有形状接触到了屏幕顶部。方块展示:PyQt5是专门为创建图形界面产生的,里面一些专门为制作游戏而开发的组件,所以PyQt5是能制作小游戏的。制作电脑游戏也是提高自己编程能力的一种很好的方式。开发没有图片,所以就自己用绘画画出来几个图形。每个游戏里都有数学模型的,这个也是。开工之前:用QtCore.QBasicTimer()创建一个游戏循环模型是一直下落的模型的运动是以小块为基础单位的,不是按像素从数学意义上来说,模型就是就是一串数字而已代码由四个类组成:Tetris, Board, Tetrominoe和Shape。Tetris类创建游戏,Board是游戏主要逻辑。Tetrominoe包含了所有的砖块,Shape是所有砖块的代码。#!/usr/bin/python3# -- coding: utf-8 --“““ZetCode PyQt5 tutorial This is a Tetris game clone.Author: Jan BodnarWebsite: zetcode.com Last edited: August 2017"““from PyQt5.QtWidgets import QMainWindow, QFrame, QDesktopWidget, QApplicationfrom PyQt5.QtCore import Qt, QBasicTimer, pyqtSignalfrom PyQt5.QtGui import QPainter, QColor import sys, randomclass Tetris(QMainWindow): def init(self): super().init() self.initUI() def initUI(self): ‘‘‘initiates application UI’’’ self.tboard = Board(self) self.setCentralWidget(self.tboard) self.statusbar = self.statusBar() self.tboard.msg2Statusbar[str].connect(self.statusbar.showMessage) self.tboard.start() self.resize(180, 380) self.center() self.setWindowTitle(‘Tetris’) self.show() def center(self): ‘‘‘centers the window on the screen’’’ screen = QDesktopWidget().screenGeometry() size = self.geometry() self.move((screen.width()-size.width())/2, (screen.height()-size.height())/2) class Board(QFrame): msg2Statusbar = pyqtSignal(str) BoardWidth = 10 BoardHeight = 22 Speed = 300 def init(self, parent): super().init(parent) self.initBoard() def initBoard(self): ‘‘‘initiates board’’’ self.timer = QBasicTimer() self.isWaitingAfterLine = False self.curX = 0 self.curY = 0 self.numLinesRemoved = 0 self.board = [] self.setFocusPolicy(Qt.StrongFocus) self.isStarted = False self.isPaused = False self.clearBoard() def shapeAt(self, x, y): ‘‘‘determines shape at the board position’’’ return self.board[(y * Board.BoardWidth) + x] def setShapeAt(self, x, y, shape): ‘‘‘sets a shape at the board’’’ self.board[(y * Board.BoardWidth) + x] = shape def squareWidth(self): ‘‘‘returns the width of one square’’’ return self.contentsRect().width() // Board.BoardWidth def squareHeight(self): ‘‘‘returns the height of one square’’’ return self.contentsRect().height() // Board.BoardHeight def start(self): ‘‘‘starts game’’’ if self.isPaused: return self.isStarted = True self.isWaitingAfterLine = False self.numLinesRemoved = 0 self.clearBoard() self.msg2Statusbar.emit(str(self.numLinesRemoved)) self.newPiece() self.timer.start(Board.Speed, self) def pause(self): ‘‘‘pauses game’’’ if not self.isStarted: return self.isPaused = not self.isPaused if self.isPaused: self.timer.stop() self.msg2Statusbar.emit(“paused”) else: self.timer.start(Board.Speed, self) self.msg2Statusbar.emit(str(self.numLinesRemoved)) self.update() def paintEvent(self, event): ‘‘‘paints all shapes of the game’’’ painter = QPainter(self) rect = self.contentsRect() boardTop = rect.bottom() - Board.BoardHeight * self.squareHeight() for i in range(Board.BoardHeight): for j in range(Board.BoardWidth): shape = self.shapeAt(j, Board.BoardHeight - i - 1) if shape != Tetrominoe.NoShape: self.drawSquare(painter, rect.left() + j * self.squareWidth(), boardTop + i * self.squareHeight(), shape) if self.curPiece.shape() != Tetrominoe.NoShape: for i in range(4): x = self.curX + self.curPiece.x(i) y = self.curY - self.curPiece.y(i) self.drawSquare(painter, rect.left() + x * self.squareWidth(), boardTop + (Board.BoardHeight - y - 1) * self.squareHeight(), self.curPiece.shape()) def keyPressEvent(self, event): ‘‘‘processes key press events’’’ if not self.isStarted or self.curPiece.shape() == Tetrominoe.NoShape: super(Board, self).keyPressEvent(event) return key = event.key() if key == Qt.Key_P: self.pause() return if self.isPaused: return elif key == Qt.Key_Left: self.tryMove(self.curPiece, self.curX - 1, self.curY) elif key == Qt.Key_Right: self.tryMove(self.curPiece, self.curX + 1, self.curY) elif key == Qt.Key_Down: self.tryMove(self.curPiece.rotateRight(), self.curX, self.curY) elif key == Qt.Key_Up: self.tryMove(self.curPiece.rotateLeft(), self.curX, self.curY) elif key == Qt.Key_Space: self.dropDown() elif key == Qt.Key_D: self.oneLineDown() else: super(Board, self).keyPressEvent(event) def timerEvent(self, event): ‘‘‘handles timer event’’’ if event.timerId() == self.timer.timerId(): if self.isWaitingAfterLine: self.isWaitingAfterLine = False self.newPiece() else: self.oneLineDown() else: super(Board, self).timerEvent(event) def clearBoard(self): ‘‘‘clears shapes from the board’’’ for i in range(Board.BoardHeight * Board.BoardWidth): self.board.append(Tetrominoe.NoShape) def dropDown(self): ‘‘‘drops down a shape’’’ newY = self.curY while newY > 0: if not self.tryMove(self.curPiece, self.curX, newY - 1): break newY -= 1 self.pieceDropped() def oneLineDown(self): ‘‘‘goes one line down with a shape’’’ if not self.tryMove(self.curPiece, self.curX, self.curY - 1): self.pieceDropped() def pieceDropped(self): ‘‘‘after dropping shape, remove full lines and create new shape’’’ for i in range(4): x = self.curX + self.curPiece.x(i) y = self.curY - self.curPiece.y(i) self.setShapeAt(x, y, self.curPiece.shape()) self.removeFullLines() if not self.isWaitingAfterLine: self.newPiece() def removeFullLines(self): ‘‘‘removes all full lines from the board’’’ numFullLines = 0 rowsToRemove = [] for i in range(Board.BoardHeight): n = 0 for j in range(Board.BoardWidth): if not self.shapeAt(j, i) == Tetrominoe.NoShape: n = n + 1 if n == 10: rowsToRemove.append(i) rowsToRemove.reverse() for m in rowsToRemove: for k in range(m, Board.BoardHeight): for l in range(Board.BoardWidth): self.setShapeAt(l, k, self.shapeAt(l, k + 1)) numFullLines = numFullLines + len(rowsToRemove) if numFullLines > 0: self.numLinesRemoved = self.numLinesRemoved + numFullLines self.msg2Statusbar.emit(str(self.numLinesRemoved)) self.isWaitingAfterLine = True self.curPiece.setShape(Tetrominoe.NoShape) self.update() def newPiece(self): ‘‘‘creates a new shape’’’ self.curPiece = Shape() self.curPiece.setRandomShape() self.curX = Board.BoardWidth // 2 + 1 self.curY = Board.BoardHeight - 1 + self.curPiece.minY() if not self.tryMove(self.curPiece, self.curX, self.curY): self.curPiece.setShape(Tetrominoe.NoShape) self.timer.stop() self.isStarted = False self.msg2Statusbar.emit(“Game over”) def tryMove(self, newPiece, newX, newY): ‘‘’tries to move a shape’’’ for i in range(4): x = newX + newPiece.x(i) y = newY - newPiece.y(i) if x < 0 or x >= Board.BoardWidth or y < 0 or y >= Board.BoardHeight: return False if self.shapeAt(x, y) != Tetrominoe.NoShape: return False self.curPiece = newPiece self.curX = newX self.curY = newY self.update() return True def drawSquare(self, painter, x, y, shape): ‘‘‘draws a square of a shape’’’ colorTable = [0x000000, 0xCC6666, 0x66CC66, 0x6666CC, 0xCCCC66, 0xCC66CC, 0x66CCCC, 0xDAAA00] color = QColor(colorTable[shape]) painter.fillRect(x + 1, y + 1, self.squareWidth() - 2, self.squareHeight() - 2, color) painter.setPen(color.lighter()) painter.drawLine(x, y + self.squareHeight() - 1, x, y) painter.drawLine(x, y, x + self.squareWidth() - 1, y) painter.setPen(color.darker()) painter.drawLine(x + 1, y + self.squareHeight() - 1, x + self.squareWidth() - 1, y + self.squareHeight() - 1) painter.drawLine(x + self.squareWidth() - 1, y + self.squareHeight() - 1, x + self.squareWidth() - 1, y + 1)class Tetrominoe(object): NoShape = 0 ZShape = 1 SShape = 2 LineShape = 3 TShape = 4 SquareShape = 5 LShape = 6 MirroredLShape = 7class Shape(object): coordsTable = ( ((0, 0), (0, 0), (0, 0), (0, 0)), ((0, -1), (0, 0), (-1, 0), (-1, 1)), ((0, -1), (0, 0), (1, 0), (1, 1)), ((0, -1), (0, 0), (0, 1), (0, 2)), ((-1, 0), (0, 0), (1, 0), (0, 1)), ((0, 0), (1, 0), (0, 1), (1, 1)), ((-1, -1), (0, -1), (0, 0), (0, 1)), ((1, -1), (0, -1), (0, 0), (0, 1)) ) def init(self): self.coords = [[0,0] for i in range(4)] self.pieceShape = Tetrominoe.NoShape self.setShape(Tetrominoe.NoShape) def shape(self): ‘‘‘returns shape’’’ return self.pieceShape def setShape(self, shape): ‘‘‘sets a shape’’’ table = Shape.coordsTable[shape] for i in range(4): for j in range(2): self.coords[i][j] = table[i][j] self.pieceShape = shape def setRandomShape(self): ‘‘‘chooses a random shape’’’ self.setShape(random.randint(1, 7)) def x(self, index): ‘‘‘returns x coordinate’’’ return self.coords[index][0] def y(self, index): ‘‘‘returns y coordinate’’’ return self.coords[index][1] def setX(self, index, x): ‘‘‘sets x coordinate’’’ self.coords[index][0] = x def setY(self, index, y): ‘‘‘sets y coordinate’’’ self.coords[index][1] = y def minX(self): ‘‘‘returns min x value’’’ m = self.coords[0][0] for i in range(4): m = min(m, self.coords[i][0]) return m def maxX(self): ‘‘‘returns max x value’’’ m = self.coords[0][0] for i in range(4): m = max(m, self.coords[i][0]) return m def minY(self): ‘‘‘returns min y value’’’ m = self.coords[0][1] for i in range(4): m = min(m, self.coords[i][1]) return m def maxY(self): ‘‘‘returns max y value’’’ m = self.coords[0][1] for i in range(4): m = max(m, self.coords[i][1]) return m def rotateLeft(self): ‘‘‘rotates shape to the left’’’ if self.pieceShape == Tetrominoe.SquareShape: return self result = Shape() result.pieceShape = self.pieceShape for i in range(4): result.setX(i, self.y(i)) result.setY(i, -self.x(i)) return result def rotateRight(self): ‘‘‘rotates shape to the right’’’ if self.pieceShape == Tetrominoe.SquareShape: return self result = Shape() result.pieceShape = self.pieceShape for i in range(4): result.setX(i, -self.y(i)) result.setY(i, self.x(i)) return resultif name == ‘main’: app = QApplication([]) tetris = Tetris() sys.exit(app.exec_())游戏很简单,所以也就很好理解。程序加载之后游戏也就直接开始了,可以用P键暂停游戏,空格键让方块直接落到最下面。游戏的速度是固定的,并没有实现加速的功能。分数就是游戏中消除的行数。self.tboard = Board(self)self.setCentralWidget(self.tboard)创建了一个Board类的实例,并设置为应用的中心组件。self.statusbar = self.statusBar() self.tboard.msg2Statusbar[str].connect(self.statusbar.showMessage)创建一个statusbar来显示三种信息:消除的行数,游戏暂停状态或者游戏结束状态。msg2Statusbar是一个自定义的信号,用在(和)Board类(交互),showMessage()方法是一个内建的,用来在statusbar上显示信息的方法。self.tboard.start()初始化游戏:class Board(QFrame): msg2Statusbar = pyqtSignal(str)… 创建了一个自定义信号msg2Statusbar,当我们想往statusbar里显示信息的时候,发出这个信号就行了。BoardWidth = 10BoardHeight = 22Speed = 300这些是Board类的变量。BoardWidth和BoardHeight分别是board的宽度和高度。Speed是游戏的速度,每300ms出现一个新的方块。…self.curX = 0self.curY = 0self.numLinesRemoved = 0self.board = []…在initBoard()里初始化了一些重要的变量。self.board定义了方块的形状和位置,取值范围是0-7。def shapeAt(self, x, y): return self.board[(y * Board.BoardWidth) + x]shapeAt()决定了board里方块的的种类。def squareWidth(self): return self.contentsRect().width() // Board.BoardWidthboard的大小可以动态的改变。所以方格的大小也应该随之变化。squareWidth()计算并返回每个块应该占用多少像素–也即Board.BoardWidth。def pause(self): ‘‘‘pauses game’’’ if not self.isStarted: return self.isPaused = not self.isPaused if self.isPaused: self.timer.stop() self.msg2Statusbar.emit(“paused”) else: self.timer.start(Board.Speed, self) self.msg2Statusbar.emit(str(self.numLinesRemoved)) self.update()pause()方法用来暂停游戏,停止计时并在statusbar上显示一条信息。def paintEvent(self, event): ‘‘‘paints all shapes of the game’’’ painter = QPainter(self) rect = self.contentsRect()…渲染是在paintEvent()方法里发生的QPainter负责PyQt5里所有低级绘画操作。for i in range(Board.BoardHeight): for j in range(Board.BoardWidth): shape = self.shapeAt(j, Board.BoardHeight - i - 1) if shape != Tetrominoe.NoShape: self.drawSquare(painter, rect.left() + j * self.squareWidth(), boardTop + i * self.squareHeight(), shape)渲染游戏分为两步。第一步是先画出所有已经落在最下面的的图,这些保存在self.board里。可以使用shapeAt()查看这个这个变量。if self.curPiece.shape() != Tetrominoe.NoShape: for i in range(4): x = self.curX + self.curPiece.x(i) y = self.curY - self.curPiece.y(i) self.drawSquare(painter, rect.left() + x * self.squareWidth(), boardTop + (Board.BoardHeight - y - 1) * self.squareHeight(), self.curPiece.shape())第二步是画出更在下落的方块。elif key == Qt.Key_Right: self.tryMove(self.curPiece, self.curX + 1, self.curY)在keyPressEvent()方法获得用户按下的按键。如果按下的是右方向键,就尝试把方块向右移动,说尝试是因为有可能到边界不能移动了。elif key == Qt.Key_Up: self.tryMove(self.curPiece.rotateLeft(), self.curX, self.curY)上方向键是把方块向左旋转一下elif key == Qt.Key_Space: self.dropDown()空格键会直接把方块放到底部elif key == Qt.Key_D: self.oneLineDown()D键是加速一次下落速度。def tryMove(self, newPiece, newX, newY): for i in range(4): x = newX + newPiece.x(i) y = newY - newPiece.y(i) if x < 0 or x >= Board.BoardWidth or y < 0 or y >= Board.BoardHeight: return False if self.shapeAt(x, y) != Tetrominoe.NoShape: return False self.curPiece = newPiece self.curX = newX self.curY = newY self.update() return TruetryMove()是尝试移动方块的方法。如果方块已经到达board的边缘或者遇到了其他方块,就返回False。否则就把方块下落到想要def timerEvent(self, event): if event.timerId() == self.timer.timerId(): if self.isWaitingAfterLine: self.isWaitingAfterLine = False self.newPiece() else: self.oneLineDown() else: super(Board, self).timerEvent(event)在计时器事件里,要么是等一个方块下落完之后创建一个新的方块,要么是让一个方块直接落到底(move a falling piece one line down)。def clearBoard(self): for i in range(Board.BoardHeight * Board.BoardWidth): self.board.append(Tetrominoe.NoShape)clearBoard()方法通过Tetrominoe.NoShape清空broad。def removeFullLines(self): numFullLines = 0 rowsToRemove = [] for i in range(Board.BoardHeight): n = 0 for j in range(Board.BoardWidth): if not self.shapeAt(j, i) == Tetrominoe.NoShape: n = n + 1 if n == 10: rowsToRemove.append(i) rowsToRemove.reverse() for m in rowsToRemove: for k in range(m, Board.BoardHeight): for l in range(Board.BoardWidth): self.setShapeAt(l, k, self.shapeAt(l, k + 1)) numFullLines = numFullLines + len(rowsToRemove) …如果方块碰到了底部,就调用removeFullLines()方法,找到所有能消除的行消除它们。消除的具体动作就是把符合条件的行消除掉之后,再把它上面的行下降一行。注意移除满行的动作是倒着来的,因为我们是按照重力来表现游戏的,如果不这样就有可能出现有些方块浮在空中的现象。def newPiece(self): self.curPiece = Shape() self.curPiece.setRandomShape() self.curX = Board.BoardWidth // 2 + 1 self.curY = Board.BoardHeight - 1 + self.curPiece.minY() if not self.tryMove(self.curPiece, self.curX, self.curY): self.curPiece.setShape(Tetrominoe.NoShape) self.timer.stop() self.isStarted = False self.msg2Statusbar.emit(“Game over”)newPiece()方法是用来创建形状随机的方块。如果随机的方块不能正确的出现在预设的位置,游戏结束。class Tetrominoe(object): NoShape = 0 ZShape = 1 SShape = 2 LineShape = 3 TShape = 4 SquareShape = 5 LShape = 6 MirroredLShape = 7Tetrominoe类保存了所有方块的形状。我们还定义了一个NoShape的空形状。Shape类保存类方块内部的信息。class Shape(object): coordsTable = ( ((0, 0), (0, 0), (0, 0), (0, 0)), ((0, -1), (0, 0), (-1, 0), (-1, 1)), … )… coordsTable元组保存了所有的方块形状的组成。是一个构成方块的坐标模版。self.coords = [[0,0] for i in range(4)]上面创建了一个新的空坐标数组,这个数组将用来保存方块的坐标。坐标系示意图:上面的图片可以帮助我们更好的理解坐标值的意义。比如元组(0, -1), (0, 0), (-1, 0), (-1, -1)代表了一个Z形状的方块。这个图表就描绘了这个形状。def rotateLeft(self): if self.pieceShape == Tetrominoe.SquareShape: return self result = Shape() result.pieceShape = self.pieceShape for i in range(4): result.setX(i, self.y(i)) result.setY(i, -self.x(i)) return resultrotateLeft()方法向右旋转一个方块。正方形的方块就没必要旋转,就直接返回了。其他的是返回一个新的,能表示这个形状旋转了的坐标。程序展示: ...

January 10, 2019 · 8 min · jiezi

hello world!——pyQT

本章学习Qt的基本功能例1,简单的窗口这个简单的小例子展示的是一个小窗口。但是我们可以在这个小窗口上面做很多事情,改变大小,最大化,最小化等,这需要很多代码才能实现。这在很多应用中很常见,没必要每次都要重写这部分代码,Qt已经提供了这些功能。PyQt5是一个高级的工具集合,相比使用低级的工具,能省略上百行代码。#!/usr/bin/python3# -- coding: utf-8 --“““ZetCode PyQt5 tutorial In this example, we create a simplewindow in PyQt5.author: Jan Bodnarwebsite: zetcode.com Last edited: August 2017"““import sysfrom PyQt5.QtWidgets import QApplication, QWidgetif name == ‘main’: app = QApplication(sys.argv) w = QWidget() w.resize(250, 150) w.move(300, 300) w.setWindowTitle(‘Simple’) w.show() sys.exit(app.exec_())运行上面的代码,能展示出一个小窗口。import sysfrom PyQt5.QtWidgets import QApplication, QWidget这里引入了PyQt5.QtWidgets模块,这个模块包含了基本的组件。app = QApplication(sys.argv)每个PyQt5应用都必须创建一个应用对象。sys.argv是一组命令行参数的列表。Python可以在shell里运行,这个参数提供对脚本控制的功能。w = QWidget()QWidge控件是一个用户界面的基本控件,它提供了基本的应用构造器。默认情况下,构造器是没有父级的,没有父级的构造器被称为窗口(window)。w.resize(250, 150)resize()方法能改变控件的大小,这里的意思是窗口宽250px,高150px。w.move(300, 300)move()是修改控件位置的的方法。它把控件放置到屏幕坐标的(300, 300)的位置。注:屏幕坐标系的原点是屏幕的左上角。w.setWindowTitle(‘Simple’)我们给这个窗口添加了一个标题,标题在标题栏展示(虽然这看起来是一句废话,但是后面还有各种栏,还是要注意一下,多了就蒙了)。w.show()show()能让控件在桌面上显示出来。控件在内存里创建,之后才能在显示器上显示出来。sys.exit(app.exec_())最后,我们进入了应用的主循环中,事件处理器这个时候开始工作。主循环从窗口上接收事件,并把事件传入到派发到应用控件里。当调用exit()方法或直接销毁主控件时,主循环就会结束。sys.exit()方法能确保主循环安全退出。外部环境能通知主控件怎么结束。exec_()之所以有个下划线,是因为exec是一个Python的关键字。程序预览:例2,带窗口图标窗口图标通常是显示在窗口的左上角,标题栏的最左边。下面的例子就是怎么用PyQt5创建一个这样的窗口。在某些环境下,图标显示不出来。如果你遇到了这个问题,看我在Stackoverfolw的回答#!/usr/bin/python3# -- coding: utf-8 --“““ZetCode PyQt5 tutorial This example shows an iconin the titlebar of the window.Author: Jan BodnarWebsite: zetcode.com Last edited: August 2017"““import sysfrom PyQt5.QtWidgets import QApplication, QWidgetfrom PyQt5.QtGui import QIconclass Example(QWidget): def init(self): super().init() self.initUI() def initUI(self): self.setGeometry(300, 300, 300, 220) self.setWindowTitle(‘Icon’) self.setWindowIcon(QIcon(‘web.png’)) self.show() if name == ‘main’: app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_())前一个例子是使用的过程式编程。Python还支持面向对象的编程:class Example(QWidget): def init(self): super().init() …面向对象编程最重要的三个部分是类(class)、数据和方法。我们创建了一个类的调用,这个类继承自QWidget。这就意味着,我们调用了两个构造器,一个是这个类本身的,一个是这个类继承的。super()构造器方法返回父级的对象。init()方法是构造器的一个方法。self.initUI() 使用initUI()方法创建一个GUI。# 自己准备一个web.pngself.setGeometry(300, 300, 300, 220)self.setWindowTitle(‘Icon’)self.setWindowIcon(QIcon(‘web.png’)) 上面的三个方法都继承自QWidget类。setGeometry()有两个作用:把窗口放到屏幕上并且设置窗口大小。参数分别代表屏幕坐标的x、y和窗口大小的宽、高。也就是说这个方法是resize()和move()的合体。最后一个方法是添加了图标。先创建一个QIcon对象,然后接受一个路径作为参数显示图标。if name == ‘main’: app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_())应用和示例的对象创立,主循环开始。程序预览:例3,提示框#!/usr/bin/python3# -- coding: utf-8 --“““ZetCode PyQt5 tutorial This example shows a tooltip on a window and a button.Author: Jan BodnarWebsite: zetcode.com Last edited: August 2017"““import sysfrom PyQt5.QtWidgets import (QWidget, QToolTip, QPushButton, QApplication)from PyQt5.QtGui import QFont class Example(QWidget): def init(self): super().init() self.initUI() def initUI(self): QToolTip.setFont(QFont(‘SansSerif’, 10)) self.setToolTip(‘This is a <b>QWidget</b> widget’) btn = QPushButton(‘Button’, self) btn.setToolTip(‘This is a <b>QPushButton</b> widget’) btn.resize(btn.sizeHint()) btn.move(50, 50) self.setGeometry(300, 300, 300, 200) self.setWindowTitle(‘Tooltips’) self.show() if name == ‘main’: app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_())在这个例子中,我们为应用创建了一个提示框。QToolTip.setFont(QFont(‘SansSerif’, 10))这个静态方法设置了提示框的字体,我们使用了10px的SansSerif字体。self.setToolTip(‘This is a <b>QWidget</b> widget’)调用setTooltip()创建提示框可以使用富文本格式的内容。btn = QPushButton(‘Button’, self)btn.setToolTip(‘This is a <b>QPushButton</b> widget’)创建一个按钮,并且为按钮添加了一个提示框。btn.resize(btn.sizeHint())btn.move(50, 50)调整按钮大小,并让按钮在屏幕上显示出来,sizeHint()方法提供了一个默认的按钮大小。程序预览:例4,关闭窗口关闭一个窗口最直观的方式就是点击标题栏的那个叉,这个例子里,我们展示的是如何用程序关闭一个窗口。这里我们将接触到一点single和slots的知识。本例使用的是QPushButton组件类。QPushButton(string text, QWidget parent = None)text参数是想要显示的按钮名称,parent参数是放在按钮上的组件,在我们的 例子里,这个参数是QWidget。应用中的组件都是一层一层(继承而来的?)的,在这个层里,大部分的组件都有自己的父级,没有父级的组件,是顶级的窗口。#!/usr/bin/python3# -- coding: utf-8 --“““ZetCode PyQt5 tutorial This program creates a quitbutton. When we press the button,the application terminates. Author: Jan BodnarWebsite: zetcode.com Last edited: August 2017"““import sysfrom PyQt5.QtWidgets import QWidget, QPushButton, QApplicationfrom PyQt5.QtCore import QCoreApplicationclass Example(QWidget): def init(self): super().init() self.initUI() def initUI(self): qbtn = QPushButton(‘Quit’, self) qbtn.clicked.connect(QCoreApplication.instance().quit) qbtn.resize(qbtn.sizeHint()) qbtn.move(50, 50) self.setGeometry(300, 300, 250, 150) self.setWindowTitle(‘Quit button’) self.show() if name == ‘main’: app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_())这里创建了一个点击之后就退出窗口的按钮。from PyQt5.QtCore import QCoreApplication程序需要QtCore对象。qbtn = QPushButton(‘Quit’, self)创建一个继承自QPushButton的按钮。第一个参数是按钮的文本,第二个参数是按钮的父级组件,这个例子中,父级组件就是我们创建的继承自Qwidget的Example类。qbtn.clicked.connect(QCoreApplication.instance().quit)事件传递系统在PyQt5内建的single和slot机制里面。点击按钮之后,信号会被捕捉并给出既定的反应。QCoreApplication包含了事件的主循环,它能添加和删除所有的事件,instance()创建了一个它的实例。QCoreApplication是在QApplication里创建的。 点击事件和能终止进程并退出应用的quit函数绑定在了一起。在发送者和接受者之间建立了通讯,发送者就是按钮,接受者就是应用对象。程序预览:例5,消息盒子默认情况下,我们点击标题栏的×按钮,QWidget就会关闭。但是有时候,我们修改默认行为。比如,如果我们打开的是一个文本编辑器,并且做了一些修改,我们就会想在关闭按钮的时候让用户进一步确认操作。#!/usr/bin/python3# -- coding: utf-8 --“““ZetCode PyQt5 tutorial This program shows a confirmation message box when we click on the closebutton of the application window. Author: Jan BodnarWebsite: zetcode.com Last edited: August 2017"““import sysfrom PyQt5.QtWidgets import QWidget, QMessageBox, QApplicationclass Example(QWidget): def init(self): super().init() self.initUI() def initUI(self): self.setGeometry(300, 300, 250, 150) self.setWindowTitle(‘Message box’) self.show() def closeEvent(self, event): reply = QMessageBox.question(self, ‘Message’, “Are you sure to quit?”, QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: event.accept() else: event.ignore() if name == ‘main’: app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_())如果关闭QWidget,就会产生一个QCloseEvent。改变控件的默认行为,就是替换掉默认的事件处理。reply = QMessageBox.question(self, ‘Message’, “Are you sure to quit?”, QMessageBox.Yes | QMessageBox.No, QMessageBox.No)我们创建了一个消息框,上面有俩按钮:Yes和No.第一个字符串显示在消息框的标题栏,第二个字符串显示在对话框,第三个参数是消息框的俩按钮,最后一个参数是默认按钮,这个按钮是默认选中的。返回值在变量reply里。if reply == QtGui.QMessageBox.Yes: event.accept()else: event.ignore()这里判断返回值,如果点击的是Yes按钮,我们就关闭组件和应用,否者就忽略关闭事件。程序预览:例6,窗口居中#!/usr/bin/python3# -- coding: utf-8 --“““ZetCode PyQt5 tutorial This program centers a window on the screen. Author: Jan BodnarWebsite: zetcode.com Last edited: August 2017"““import sysfrom PyQt5.QtWidgets import QWidget, QDesktopWidget, QApplicationclass Example(QWidget): def init(self): super().init() self.initUI() def initUI(self): self.resize(250, 150) self.center() self.setWindowTitle(‘Center’) self.show() def center(self): qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) if name == ‘main’: app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_())QtGui.QDesktopWidget提供了用户的桌面信息,包括屏幕的大小。self.center()这个方法是调用我们下面写的,实现对话框居中的方法。qr = self.frameGeometry()得到了主窗口的大小。cp = QDesktopWidget().availableGeometry().center()获取显示器的分辨率,然后得到中间点的位置。qr.moveCenter(cp)然后把自己窗口的中心点放置到qr的中心点。self.move(qr.topLeft())然后把窗口的坐上角的坐标设置为qr的矩形左上角的坐标,这样就把窗口居中了。程序预览: ...

January 10, 2019 · 3 min · jiezi

事件和信号——pyQT5

事件和信号事件signals and slots 被其他人翻译成信号和槽机制,(⊙o⊙)…我这里还是不翻译好了。所有的应用都是事件驱动的。事件大部分都是由用户的行为产生的,当然也有其他的事件产生方式,比如网络的连接,窗口管理器或者定时器等。调用应用的exec_()方法时,应用会进入主循环,主循环会监听和分发事件。在事件模型中,有三个角色:事件源事件事件目标事件源就是发生了状态改变的对象。事件是这个对象状态改变的内容。事件目标是事件想作用的目标。事件源绑定事件处理函数,然后作用于事件目标身上。PyQt5处理事件方面有个signal and slot机制。Signals and slots用于对象间的通讯。事件触发的时候,发生一个signal,slot是用来被Python调用的(相当于一个句柄?这个词也好恶心,就是相当于事件的绑定函数)slot只有在事件触发的时候才能调用。Signals & slots下面是signal & slot的演示#!/usr/bin/python3# -- coding: utf-8 --“““ZetCode PyQt5 tutorial In this example, we connect a signalof a QSlider to a slot of a QLCDNumber. Author: Jan BodnarWebsite: zetcode.com Last edited: January 2017"““import sysfrom PyQt5.QtCore import Qtfrom PyQt5.QtWidgets import (QWidget, QLCDNumber, QSlider, QVBoxLayout, QApplication)class Example(QWidget): def init(self): super().init() self.initUI() def initUI(self): lcd = QLCDNumber(self) sld = QSlider(Qt.Horizontal, self) vbox = QVBoxLayout() vbox.addWidget(lcd) vbox.addWidget(sld) self.setLayout(vbox) sld.valueChanged.connect(lcd.display) self.setGeometry(300, 300, 250, 150) self.setWindowTitle(‘Signal and slot’) self.show() if name == ‘main’: app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_())上面的例子中,显示了QtGui.QLCDNumber和QtGui.QSlider模块,我们能拖动滑块让数字跟着发生改变。sld.valueChanged.connect(lcd.display)这里是把滑块的变化和数字的变化绑定在一起。sender是信号的发送者,receiver是信号的接收者,slot是对这个信号应该做出的反应。程序展示:重构事件处理器在PyQt5中,事件处理器经常被重写(也就是用自己的覆盖库自带的)。#!/usr/bin/python3# -- coding: utf-8 --“““ZetCode PyQt5 tutorial In this example, we reimplement an event handler. Author: Jan BodnarWebsite: zetcode.com Last edited: August 2017"““import sysfrom PyQt5.QtCore import Qtfrom PyQt5.QtWidgets import QWidget, QApplicationclass Example(QWidget): def init(self): super().init() self.initUI() def initUI(self): self.setGeometry(300, 300, 250, 150) self.setWindowTitle(‘Event handler’) self.show() def keyPressEvent(self, e): if e.key() == Qt.Key_Escape: self.close() if name == ‘main’: app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_())这个例子中,我们替换了事件处理器函数keyPressEvent()。def keyPressEvent(self, e): if e.key() == Qt.Key_Escape: self.close()此时如果按下ESC键程序就会退出。程序展示:这个就一个框,啥也没,就不展示了。事件对象事件对象是用python来描述一系列的事件自身属性的对象。#!/usr/bin/python3# -- coding: utf-8 --“““ZetCode PyQt5 tutorial In this example, we display the x and y coordinates of a mouse pointer in a label widget.Author: Jan BodnarWebsite: zetcode.com Last edited: August 2017"““import sysfrom PyQt5.QtCore import Qtfrom PyQt5.QtWidgets import QWidget, QApplication, QGridLayout, QLabelclass Example(QWidget): def init(self): super().init() self.initUI() def initUI(self): grid = QGridLayout() grid.setSpacing(10) x = 0 y = 0 self.text = “x: {0}, y: {1}".format(x, y) self.label = QLabel(self.text, self) grid.addWidget(self.label, 0, 0, Qt.AlignTop) self.setMouseTracking(True) self.setLayout(grid) self.setGeometry(300, 300, 350, 200) self.setWindowTitle(‘Event object’) self.show() def mouseMoveEvent(self, e): x = e.x() y = e.y() text = “x: {0}, y: {1}".format(x, y) self.label.setText(text) if name == ‘main’: app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_())这个示例中,我们在一个组件里显示鼠标的X和Y坐标。self.text = “x: {0}, y: {1}".format(x, y)self.label = QLabel(self.text, self)X Y坐标显示在QLabel组件里self.setMouseTracking(True)鼠标追踪默认没有开启,当有鼠标点击事件发生后才会开启。def mouseMoveEvent(self, e): x = e.x() y = e.y() text = “x: {0}, y: {1}".format(x, y) self.label.setText(text)e代表了事件对象。里面有我们触发事件(鼠标移动)的事件对象。x()和y()方法得到鼠标的x和y坐标点,然后拼成字符串输出到QLabel组件里。程序展示:事件发送有时候我们会想知道是哪个组件发出了一个信号,PyQt5里的sender()方法能搞定这件事。#!/usr/bin/python3# -- coding: utf-8 --“““ZetCode PyQt5 tutorial In this example, we determine the event senderobject.Author: Jan BodnarWebsite: zetcode.com Last edited: August 2017"““import sysfrom PyQt5.QtWidgets import QMainWindow, QPushButton, QApplicationclass Example(QMainWindow): def init(self): super().init() self.initUI() def initUI(self): btn1 = QPushButton(“Button 1”, self) btn1.move(30, 50) btn2 = QPushButton(“Button 2”, self) btn2.move(150, 50) btn1.clicked.connect(self.buttonClicked) btn2.clicked.connect(self.buttonClicked) self.statusBar() self.setGeometry(300, 300, 290, 150) self.setWindowTitle(‘Event sender’) self.show() def buttonClicked(self): sender = self.sender() self.statusBar().showMessage(sender.text() + ’ was pressed’) if name == ‘main’: app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_())这个例子里有俩按钮,buttonClicked()方法决定了是哪个按钮能调用sender()方法。btn1.clicked.connect(self.buttonClicked) btn2.clicked.connect(self.buttonClicked)两个按钮都和同一个slot绑定。def buttonClicked(self): sender = self.sender() self.statusBar().showMessage(sender.text() + ’ was pressed’)我们用调用sender()方法的方式决定了事件源。状态栏显示了被点击的按钮。程序展示:信号发送QObject实例能发送事件信号。下面的例子是发送自定义的信号。#!/usr/bin/python3# -- coding: utf-8 --“““ZetCode PyQt5 tutorial In this example, we show how to emit a custom signal. Author: Jan BodnarWebsite: zetcode.com Last edited: August 2017"““import sysfrom PyQt5.QtCore import pyqtSignal, QObjectfrom PyQt5.QtWidgets import QMainWindow, QApplicationclass Communicate(QObject): closeApp = pyqtSignal() class Example(QMainWindow): def init(self): super().init() self.initUI() def initUI(self): self.c = Communicate() self.c.closeApp.connect(self.close) self.setGeometry(300, 300, 290, 150) self.setWindowTitle(‘Emit signal’) self.show() def mousePressEvent(self, event): self.c.closeApp.emit() if name == ‘main’: app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_())我们创建了一个叫closeApp的信号,这个信号会在鼠标按下的时候触发,事件与QMainWindow绑定。class Communicate(QObject): closeApp = pyqtSignal()Communicate类创建了一个pyqtSignal()属性的信号。self.c = Communicate()self.c.closeApp.connect(self.close) closeApp信号QMainWindow的close()方法绑定。def mousePressEvent(self, event): self.c.closeApp.emit()点击窗口的时候,发送closeApp信号,程序终止。程序展示:这个也是啥也没。 ...

January 10, 2019 · 3 min · jiezi

PyQt5 内嵌浏览器注入 Javascript 脚本实现自动化操作

概要应同学邀请,演示如何使用 PyQt5 内嵌浏览器浏览网页,并注入 Javascript 脚本实现自动化操作。sg 原贴地址: 如何在Python利用runJavaScript模拟鼠标移动页面的某个元素https://segmentfault.com/q/10…下面测试的是一个廉价机票预订网站(http://www.flyscoot.com/),关键点如下使用 QWebEngineView 加载网页,并显示进度。在默认配置(QWebEngineProfile)中植入 Javascript 内容,这样脚本会在所有打开的网页中执行,不论跳转到哪个网址。Javascript 脚本使用网址中的路径名,判断当前网页位置,从而决定执行哪种操作。python 代码示例#!/usr/bin/env python3# -- coding: utf-8 --‘‘‘使用 PyQt5 内嵌浏览器浏览网页,并注入 Javascript 脚本实现自动化操作。‘‘‘import osimport sysfrom datetime import datetimefrom PyQt5.QtWidgets import ( QWidget, QApplication, QVBoxLayout, QHBoxLayout, QDesktopWidget, QTextEdit, QLabel, QLineEdit, QPushButton, QFileDialog, QProgressBar,)from PyQt5.QtCore import QUrl, pyqtSlotfrom PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEngineProfile, QWebEngineScript, QWebEnginePageclass Browser(QWidget): def init(self): super().init() self.init_ui() # 脚本 self.profile = QWebEngineProfile.defaultProfile() self.script = QWebEngineScript() self.prepare_script() def init_ui(self): self.webView = QWebEngineView() self.logEdit = QTextEdit() self.logEdit.setFixedHeight(100) self.addrEdit = QLineEdit() self.addrEdit.returnPressed.connect(self.load_url) self.webView.urlChanged.connect( lambda i: self.addrEdit.setText(i.toDisplayString())) self.jsEdit = QLineEdit() self.jsEdit.setText(‘inject.js’) loadUrlBtn = QPushButton(‘加载’) loadUrlBtn.clicked.connect(self.load_url) chooseJsBtn = QPushButton(‘选择脚本文件’) chooseJsBtn.clicked.connect(self.choose_js_file) # 导航/工具 top = QWidget() top.setFixedHeight(80) topBox = QVBoxLayout(top) topBox.setSpacing(0) topBox.setContentsMargins(5, 0, 0, 5) progBar = QProgressBar() progBox = QHBoxLayout() progBox.addWidget(progBar) topBox.addLayout(progBox) naviBox = QHBoxLayout() naviBox.addWidget(QLabel(‘网址’)) naviBox.addWidget(self.addrEdit) naviBox.addWidget(loadUrlBtn) topBox.addLayout(naviBox) naviBox = QHBoxLayout() naviBox.addWidget(QLabel(‘注入脚本文件’)) naviBox.addWidget(self.jsEdit) naviBox.addWidget(chooseJsBtn) topBox.addLayout(naviBox) self.webView.loadProgress.connect(progBar.setValue) # 主界面 layout = QVBoxLayout(self) layout.addWidget(self.webView) layout.addWidget(top) layout.addWidget(self.logEdit) self.show() self.resize(1024, 900) self.center() def center(self): qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) @pyqtSlot() def load_url(self): url = self.addrEdit.text().strip() if not url.lower().startswith(‘http://’) and not url.lower().startswith(‘https://’): url = ‘http://{}’.format(url) self.load(url) @pyqtSlot() def choose_js_file(self): f, _ = QFileDialog.getOpenFileName(filter=“Javascript files(*.js)”) if os.path.isfile(f): self.jsEdit.setText(f) self.prepare_script() def prepare_script(self): path = self.jsEdit.text().strip() if not os.path.isfile(path): self.log(‘invalid js path’) return self.profile.scripts().remove(self.script) with open(path, ‘r’) as f: self.script.setSourceCode(f.read()) self.profile.scripts().insert(self.script) self.log(‘injected js ready’) def log(self, msg, *args, **kwargs): m = msg.format(*args, **kwargs) self.logEdit.append(’{} {}’.format( datetime.now().strftime(’%H:%M:%S’), m)) def load(self, url): self.log(f’loading {url}’) self.addrEdit.setText(url) self.webView.load(QUrl(url))if name == ‘main’: app = QApplication(sys.argv) b = Browser() b.load(‘http://www.flyscoot.com/') sys.exit(app.exec_())Javascript 脚本示例// 简单起见,这里只演示部分页面,脚本内容摘自 Heng丶原贴文。function handle(path) { // 首页 if (path == ‘/zh’) { document.getElementsByClassName(‘radio-inline’)[1].click(); document.getElementById(‘oneway_from’).value=‘广州 (CAN)’; document.getElementById(‘oneway_to’).value=‘新加坡 (SIN)’; document.getElementById(‘oneway_departuredate’).value=‘2018年9月10日’; document.getElementsByClassName(‘btn–booking’)[1].click(); return; } // 选择航班 if (path == ‘/Book/Flight’) { document.getElementsByClassName(‘price–sale’)[0].click(); document.getElementsByClassName(‘heading-4’)[0].click(); document.getElementsByClassName(‘btn-submit’)[0].click(); return; } // 乘客信息 if (path == ‘/BookFlight/Passengers’) { document.getElementsByClassName(‘fname1’)[0].value = “匿名”; }}let host = document.location.hostname;if (host.endsWith(’.flyscoot.com’)) { handle(document.location.pathname);} ...

September 1, 2018 · 2 min · jiezi