Project structure
MOC (meta object compiler) is used for meta object code generation and is applicable to * h,.cpp file, when scanned Q in H file_ The object macro generates a moc_xxx.cpp code and write the dependencies to Makefile. uic(User Interface Compiler) is used for Widget layout generation and is applicable to ui file, rcc(Resource Compiler) is used for virtual file system content generation, applicable to * qrc file.
- Managing projects with cmake
project(Test LANGUAGES CXX) set(CMAKE_PREFIX_PATH "/home/van/Qt/5.12.11/gcc_64") file(GLOB_RECURSE QRC_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.qrc) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) #set(QRC_SOURCE_FILES Resources.qrc) find_package(Qt5 COMPONENTS Widgets REQUIRED) qt5_add_resources(QRC_FILES ${QRC_SOURCE_FILES}) SOURCE_GROUP("Resource Files" FILES ${QRC_SOURCE_FILES}) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/linux_include) qt5_wrap_cpp(mocfiles mycamera.h) add_executable(Test main.cpp ${QRC_FILES} BaslerCamera/mycamera.cpp BaslerCamera/mycamera.h customgraphicsitem.cpp fullscreenvideo.cpp iconbutton.cpp mainwindow.cpp BaslerCamera/sbaslercameracontrol.cpp onevideo.cpp qwcomboboxdelegate.cpp qwfloatspindelegate.cpp qwintspindelegate.cpp DarkStyle.cpp # ${mocfiles} ) LINK_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR}/lib/linux_64) set(LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/lib/linux_64) find_library(CAMER_LIB_1 libGCBase_gcc_v3_1_Basler_pylon.so ${LIB_DIR}) find_library(CAMER_LIB_2 libGenApi_gcc_v3_1_Basler_pylon.so ${LIB_DIR}) find_library(CAMER_LIB_3 libpylonbase-6.1.1.so ${LIB_DIR}) find_library(CAMER_LIB_4 libpylonutility-6.1.1.so ${LIB_DIR}) #find_library(RUNTIME_LIB rt ${CMAKE_CURRENT_SOURCE_DIR}/lib/linux_64 ${CMAKE_CURRENT_SOURCE_DIR}/lib/Qt ) MESSAGE(${CAMER_LIB_1}) MESSAGE(${CAMER_LIB_2}) MESSAGE(${CAMER_LIB_3}) MESSAGE(${CAMER_LIB_4}) target_link_libraries(Test Qt5::Widgets ${CAMER_LIB_1} ${CAMER_LIB_2} ${CAMER_LIB_3} ${CAMER_LIB_4} )
The above is cmakelists of a qt project
- ui file
The ui file is created by the user for the Qmainwindow or Qwidget class to record the types and styles of internal sub windows or spaces.
Assuming that the user class inherits from the Qwidget and is named XXX, UIC will be based on XXX UI file generation ui_xxx.h header file and let XXX CPP contains. During initialization of XXX class, UI is used_ The XXX class initializes the member variable UI, and then calls ui->setupUi (this) to really let the XXX class contain those sub windows and controls recorded in the UI file. After that, these sub windows and controls can be obtained in the form of UI - >.
If you want to view the QT source code, add the QT source code path to the cmake file of the project
include_directories("/home/xxx/Qt/5.12.11/Src"), although you can't jump directly, when you press ctrl to add the function name, you will search in the source path.
Meta object and event framework
If you want to use meta objects, the class definition must be placed in the header file, inherited from Qobject, and include Q in the class definition_ The object macro is used to add the virtual function metaObject() to the class and identify other macros such as slot signal. And moc_xxx.cpp is responsible for implementing virtual functions. If you want to reflect a member function of a class, you need to add Q before the function declaration_ Invokable macro.
You can know the inheritance relationship between classes through reflection.
You can also get the parameters and return types of member functions, but these types cannot be user-defined classes. For example, the following example will report an error at run time
#ifndef TEST_QOBJECT_H #define TEST_QOBJECT_H #include<QObject> class B; class A:public QObject{ /*To use metaobject, the system must inherit from the QObject class, and QObject should be in the base class Inherit the first place in the list.*/ Q_OBJECT //Start the meta object system. Q_ The object must be located in a private area. public: A(){qDebug("initialize A\n");} }; //class A:public QObject{Q_OBJECT}; class B:public QObject{ Q_OBJECT public: B(){qDebug("initialize B\n");} Q_INVOKABLE A* g(int i,float j,A* a){return a;} }; class C:public QObject{Q_OBJECT}; class D:public C{Q_OBJECT}; #endif //TEST_QOBJECT_H
int main(){ A ma; B mb; const QMetaObject *pa=ma.metaObject(); const QMetaObject *pb=mb.metaObject(); QMetaMethod m=pb->method(pb->indexOfMethod("g(int,float)")); QByteArray s= m.name(); //Gets the function name of the member function g. cout<<s.data()<<endl; //Output g s=m.methodSignature(); //Get the signature of function g cout<<s.data()<<endl; //Output g(int,float) auto i=m.methodType(); /*Get the type of function g, where the enumeration value defined in QMetaMethod::MethodType is returned, Where Method=0 indicates that the type is a member function*/ cout<<i<<endl; //Output 0 (for member function). //The following information relates to the return type of the function s=m.typeName(); //Gets the type name of the return value of the function g cout<<s.data()<<endl; //Output void auto j=m.returnType(); /*Gets the type of the function g return value. The type here is the enumeration value defined in QMetaType, where enumeration Value QMetaType::void=43*/ cout<<j<<endl; //Output 43 //The following information relates to the parameters of the function auto k=m.parameterType(1); /*Gets the parameter type with index number 1 in function g, where the type is defined in QMetaType Enumeration value, where enumeration value QMetaType::float=38*/ cout<<k<<endl; //Output 38 QList<QByteArray> q=m.parameterNames(); //Gets a list of parameter names for the function g cout<<q[0].data()<<q[1].data()<<endl; //Output ij q=m.parameterTypes(); //Gets a list of parameter types for the function g. cout<<q[0].data()<<q[1].data()<<endl; //Output intfloat return 0; }
Qvariant can be used to save a custom type, provided that the type must pass Q_ DECLARE_ Register with metatype. When the member variable of a class uses Q_ After property is declared, it is also called the property of the class, which can be accessed through instance The property ("x") method uses the variable name to get a copy of the property and store it in qvariant. Therefore, as a property, a custom class must have a public default constructor and copy function. You can also use instance Setproperty ("x", v) or add new properties dynamically. The dynamic property belongs to the instance, so it will not have anything to do with the class meta object (QmetaObject). Changing the value of the dynamic property will send qddynamicpropertychangeevent to the object.
The objects in QT are organized in the form of an object tree. The parent object uses the Qobject pointer to save the references of its child objects. A child object can only have one parent object. When the parent object is destructed, its child object will be automatically deleted. When the child object is deleted, the child object will be removed from the list of parent objects. When an object is deleted, a destroyed() signal will be sent
Here is a problem. Suppose that a and B are created in order on the stack, and the parent object of a is set to B. when leaving the scope, B destructs first, and it will call the destructor of A. Then a will call the destructor again, causing a double free error. Therefore, generally, only the top-level parent class is located on the stack, and other child objects are located on the heap.
An event loop will be carried out in exec() of the QApplication object, and notify() will be called to distribute the event to the corresponding object. The object's interface for handling the event is event(), which will call different event handling functions according to different events. Event() returns true, indicating that the event has been accepted and processed, otherwise it will be further distributed to the parent object, Until this event is processed or reaches the top-level object.
#include <QApplication> #include<QWidget> #include<QObject> #include <iostream> using namespace std; class A:public QWidget{public: bool event(QEvent* e); //Event processing method 1: rewrite the virtual function QObject::event() void mousePressEvent(QMouseEvent* e); };//Event handling method 2: override this virtual function in the QWidget class bool A::event(QEvent* e){ static int i=0; //i for counting cout<<"E"<<i++<<endl; //Verify that the function can be captured before the event reaches the target object if(e->type()==QEvent::KeyPress) //Determine whether it is a keyboard press event. cout<<"keyDwon"<<endl; return QWidget::event(e); /*The event function of the parent class should be called here to process the unhandled event. If not, the If the event of the parent class is called, the contents in the mousePressEvent processing function in this example will not be changed Executed. Readers can return 1 or 0 here for verification.*/ } void A::mousePressEvent(QMouseEvent* e){//Handle mouse down events, which is the simplest event handling method in Qt. cout<<"mouseDwon"<<endl; } int main(int argc, char *argv[]){ QApplication a(argc,argv); //There can only be one object of type QApplication in Qt A ma; //Create an assembly ma.resize(333,222); //Sets the size of the assembly ma.show(); //Displays the created assembly a.exec(); //Enter the event main loop here. return 0; }
In the above example, the overloaded event will eventually call the event function of the Qwidget, and the overloaded mousePressEvent event handler will be called.
It is useless to call QEvent::accept() or QEvent::accept() in event(), because they are used for communication between event handler and event(), and the communication between event() and notify() can directly use the return value of bool.
The event filter is used to send events that should have been distributed to the target object to the observer object. It is processed by the observer's eventFilter function. If false is returned, the event will be returned to the target object. In the case of multiple observers, if true, it will be passed to the next observer. The last registered observer will be activated first. In the case of a single observer, if true, it will not be returned to the target object.
#include<QMouseEvent> #include<QPushButton> #include<QObject> #include <iostream> using namespace std; class A:public QObject{public: //The object of this class is used as a filter object, and the use of event filter needs to inherit QObject bool eventFilter(QObject *w, QEvent *e){ if(e->type()==QEvent::MouseButtonPress) {cout<<w->objectName().toStdString(); //Verify that w is the target object that the event should have reached cout<<"=Ak"<<endl; return 1; //Returning 1 indicates that the event will not be processed further } return 0;} /*Returning 0 means that other events are returned to the target object for processing. This example should return 0, otherwise the event is added The safety button of the filter will not be displayed.*/ }; class B:public A{public: //Inherited from Class A bool eventFilter(QObject *w, QEvent *e){ if(e->type()==QEvent::MouseButtonPress){ cout<<w->objectName().toStdString()<<"=Bk"<<endl; return 0;} return 0;} }; class C:public QWidget{public: void mousePressEvent(QMouseEvent *e){cout<<"Ck"<<endl;}}; class D:public QPushButton{public:void mousePressEvent(QMouseEvent *e){cout<<"DK"<<endl;}}; int main(int argc, char *argv[]){ QApplication a(argc,argv); //To create an object, note: the parent object of this example should be created first to avoid premature end of life A ma; B mb; C mc; D *pd=new D; D *pd1=new D; pd->setText("AAA"); pd->move(22,22); pd1->setText("BBB"); pd1->move(99,22); //Set object name ma.setObjectName("ma"); mb.setObjectName("mb"); mc.setObjectName("mc"); pd->setObjectName("pd"); pd1->setObjectName("pd1"); //Set parent object pd->setParent(&mc); pd1->setParent(&mc); mb.setParent(&ma); //① //Register filter object pd->installEventFilter(&mb); //② pd1->installEventFilter(&ma); //③ mc.resize(333,222); mc.show(); a.exec(); return 0; }
There are two kinds of custom events. One is postevent, which will be added to the event queue and arranged according to priority. sendEvent is sent directly to the target object. Therefore, the postevent must be created on the heap. After the event is published, its ownership belongs to the event queue
Assuming that a window has multiple buttons with similar functions, it will be troublesome to write a slot function for each button. It is more convenient to bind the signals of each button to the same QSignalMapper, and then use the same slot function for processing. To distinguish these buttons, you can bind the buttons to an integer or string with setMapping in advance.
void Widget::InitUi() { names << "Song Jiang" << "Lu Junyi" << "Wu Yong" << "Gongsun Sheng" << "Guan Sheng" << "Lin Chong" << "Qin Ming" << "Hu yanzhuo" << "Hua Rong" << "Chai Jin" << "Li Ying" << "Zhu Tong" << "lu zhishen" << "Wu Song" << "Dong Ping" << "Zhang Qing"; QGridLayout *gridLayout = new QGridLayout; for (int i = 0; i < names.size(); ++i) { QPushButton *button = new QPushButton(names[i]); // Use the setMapping() function to associate a specific integer or string or object (qt doc screenshot) with a specific object. signalMapper->setMapping(button, names[i]); // This is how you can connect the signal of the object to the map() slot function of the QSignalMapper object connect(button, SIGNAL(clicked()), signalMapper, SLOT(map())); gridLayout->addWidget(button, i / 4, i % 4); } // Connect the slot function defined by us to the mapped() signal. / / pay attention to the way mapped is written connect(signalMapper, SIGNAL(mapped(QString)),this, SLOT(ShowName(QString))); setLayout(gridLayout); }
Model view
QT uses agents to transfer data between models and views.
QWFloatSpinDelegate::QWFloatSpinDelegate(QObject *parent):QStyledItemDelegate(parent) { } QWidget *QWFloatSpinDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { QDoubleSpinBox *editor = new QDoubleSpinBox(parent); editor->setFrame(false); editor->setMinimum(0); editor->setDecimals(2); editor->setMaximum(10000); return editor; } void QWFloatSpinDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { float value = index.model()->data(index, Qt::EditRole).toFloat(); QDoubleSpinBox *spinBox = static_cast<QDoubleSpinBox*>(editor); spinBox->setValue(value); } void QWFloatSpinDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QDoubleSpinBox *spinBox = static_cast<QDoubleSpinBox*>(editor); spinBox->interpretText(); float value = spinBox->value(); QString str=QString::asprintf("%.2f",value); model->setData(index, str, Qt::EditRole); } void QWFloatSpinDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const { editor->setGeometry(option.rect); qDebug() << editor->rect(); }
The above is a spinbox agent. When the data in the view is updated, it will call setmodelData to synchronize the update to the model. On the contrary, when the data in the model is updated, it will call seteditordata In the seteditordata parameter, index is used to retrieve and export the updated data items in the model. editor is a window component responsible for displaying the data items corresponding to index. Here is a spinbox.
mapping
Using qppainter, you can draw on different drawing devices, including QWidget, QPixmap, QImage, etc. For QWidget, Qpainter can only be used in its paintEven function.
Graphics view architecture is convenient to draw graphics composed of multiple graphics components, and each component can be selected and modified. Graphics view consists of three parts: scene, view and graphic item.
The coordinate unit of QGraphicsView is pixels, and the upper left corner is (0,0). QGraphicsScene can be regarded as the parent of all top-level graphics items, and can set the coordinates of the upper left corner and the length and width. If the scene is bound to a view, the scene will fill the view. The scene is used to manage the status of each graphic item and pass events to each graphic item. The view is used to display the content in the scene. You can set multiple different views for a scene. Each QGraphicsItem uses its own coordinate system, usually with a center of 0,0. QGraphicsItem::pos() returns the coordinates of the center of the graphic item in the parent coordinate system. If it is the top level, it returns the coordinates in the scene. Each graphic item has a location coordinate and a rectangular bounding box in the scene.
scene itself has no event handling function. It is only responsible for forwarding the event of view to the internal item through sendEvent scene can manage internally selected or focused items. The focused item can receive keyboard events. The zvalue attribute is used to judge the relationship between items. In the case of stacking, only the item with the largest zvalue can obtain focus and select.
#include <QApplication> #include <QGraphicsScene> #include <QGraphicsView> #include <QGraphicsRectItem> #include "math.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); QGraphicsScene scene; // Define a scene and set the background color to red // scene.setBackgroundBrush(Qt::red); QPen pen; // Define a brush and set the color and width of the brush pen.setColor(QColor(0, 160, 230)); pen.setWidth(10); QGraphicsRectItem *m_rectItem = new QGraphicsRectItem(); // Define a rectangular element m_rectItem->setRect(0, 0, 80, 80); m_rectItem->setPen(pen); m_rectItem->setBrush(QBrush(QColor(0, 0, 255))); m_rectItem->setFlag(QGraphicsItem::ItemIsMovable); QGraphicsLineItem *m_lineItem = new QGraphicsLineItem(); // Define a line entity m_lineItem->setLine(QLineF(0, 0, 100, 100)); m_lineItem->setPen(pen); m_lineItem->setFlag(QGraphicsItem::ItemIsMovable); QGraphicsPathItem *m_pathItem = new QGraphicsPathItem(); // Define a path entity QPainterPath path; path.moveTo(0, 0); for (int i = 1; i < 5; ++i) { path.lineTo(50 + 40 * cos(0.8 * i * M_PI), 50 + 40 * sin(0.8 * i * M_PI)); } path.closeSubpath(); m_pathItem->setPath(path); m_pathItem->setPen(pen); m_pathItem->setFlag(QGraphicsItem::ItemIsMovable); QGraphicsPolygonItem *m_polygonItem = new QGraphicsPolygonItem(); // Define a polygon primitive QPolygonF polygon; polygon << QPointF(-100.0, -150.0) << QPointF(-120.0, 150.0) << QPointF(320.0, 160.0) << QPointF(220.0, -140.0); m_polygonItem->setPolygon(polygon); m_polygonItem->setPen(pen); m_polygonItem->setFlag(QGraphicsItem::ItemIsMovable); scene.addItem(m_rectItem); // Add rectangular primitives to the scene scene.addItem(m_lineItem); // Add line primitives to the scene scene.addItem(m_pathItem); // Add path primitives to the scene scene.addItem(m_polygonItem); // Add polygon primitives to the scene QGraphicsView view(&scene); // Define a view and add the scene to the view view.resize(1024, 768); view.show(); return a.exec(); }