简体   繁体   English

Qt和C ++-我自己的类和信号/插槽

[英]Qt and C++ - my own class and signals/slots

I've started learning Qt with C++ by writing a simple GUI. 我已经通过编写简单的GUI开始使用C ++学习Qt。 At the beginning, after I had learnt mechanism of signals and slots I decided to write program which gives us ability to control industrial robot arm. 在开始学习信号和插槽的机制后,我决定编写程序,使我们能够控制工业机器人手臂。 So the idea is simple: We've 6 buttons and depending on which one we pressed, then a text appears describing what have we done; 这样的想法很简单:我们有6个按钮,并根据按下的按钮而不同,然后出现一个文本,描述我们做了什么。 for example: "Arm moved to the left". 例如:“手臂移到左侧”。

I am going to build it up but first I have some questions to you. 我要进行构建,但是首先我要向您提出一些问题。

Here is my code: 这是我的代码:

Arm.h: Arm.h:

#ifndef ARM_H
#define ARM_H

#include <QVector>
#include <QString>
#include <QLabel>

 class Arm{

public:
 Arm();
 static void displayMoves(QLabel *ptrQLabel);  //function for display         QString listMoves
    QVector<bool(*)(void)> vctrMovesFun; //contains pointers for function which defines moves of industrial robot

private:
 static QString listMoves; //contain every move which industrial robot has done

 static bool moveArmForward();
 static bool moveArmBackward();
 static bool moveArmLeft();
 static bool moveArmRight();
 static bool spinArmLeft();
 static bool spinArmRight();  //all this functions define moves of robot's arm
};

#endif // ARM_H

Arm.cpp: Arm.cpp:

#include "arm.h"

QString Arm::listMoves = ""; //empty string
//***************************************************************
Arm::Arm(){
 vctrMovesFun = {&moveArmForward, &moveArmBackward, &moveArmLeft,
                 &moveArmRight, &spinArmLeft, &spinArmRight}; //set reference to functions
}
//***************************************************************
bool Arm::moveArmForward(){
listMoves+= "Arm moved forward\n";
return true;}
//***************************************************************
bool Arm::moveArmBackward(){
listMoves+= "Arm moved backward\n";
return true;}
//***************************************************************
bool Arm::moveArmLeft(){
listMoves+= "Arm moved to the left\n";
return true;}
//***************************************************************
bool Arm::moveArmRight(){
listMoves+= "Arm moved to the right\n";
return true;}
//***************************************************************
bool Arm::spinArmLeft(){
listMoves+= "Arm spinned to the left\n";
return true;}
//***************************************************************
bool Arm::spinArmRight(){
listMoves+= "Arm spinned to the right\n";
return true;}
//***************************************************************
void Arm::displayMoves(QLabel *ptrQLabel){
ptrQLabel -> setText(listMoves);
}

MainWindow.h: MainWindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include "arm.h"

#include <QMainWindow>
#include <QPushButton>

namespace Ui {
class MainWindow;}

class MainWindow : public QMainWindow{
Q_OBJECT

public:
 explicit MainWindow(QWidget *parent = 0);
 ~MainWindow();

private:
 Ui::MainWindow *ui;
 QPushButton *button0;
 QPushButton *button1;
 QPushButton *button2;
 QPushButton *button3;
 QPushButton *button4;
 QPushButton *button5;

 QLabel *label;

 Arm arm;

private slots:
 void useVector0();
 void useVector1();
 void useVector2();
 void useVector3();
 void useVector4();
 void useVector5();

};

#endif // MAINWINDOW_H

MainWindow.cpp: MainWindow.cpp:

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
 QMainWindow(parent),
 ui(new Ui::MainWindow)
{
 ui -> setupUi(this);
 this -> setGeometry(0,0,800,700);
 this -> setStyleSheet("background-color:rgb(188, 198 ,204)");

 button0 = new QPushButton("Move forward", this);
 button0 -> setGeometry(50,50, 100,50);
 button0 -> setStyleSheet("background-color:rgb(108, 118, 143)");
 connect(button0, SIGNAL (clicked()), this, SLOT (useVector0()));

 button1 = new QPushButton("Move backward", this);
 button1 -> setGeometry(50,150, 100,50);
 button1 -> setStyleSheet("background-color:rgb(108, 118, 143)");
 connect(button1, SIGNAL (clicked()), this, SLOT (useVector1()));

 button2 = new QPushButton("Move left", this);
 button2 -> setGeometry(50,250, 100,50);
 button2 -> setStyleSheet("background-color:rgb(108, 118, 143)");
 connect(button2, SIGNAL (clicked()), this, SLOT (useVector2()));

 button3 = new QPushButton("Move right", this);
 button3 -> setGeometry(50,350, 100,50);
 button3 -> setStyleSheet("background-color:rgb(108, 118, 143)");
 connect(button3, SIGNAL (clicked()), this, SLOT (useVector3()));

 button4 = new QPushButton("Spin left", this);
 button4 -> setGeometry(50,450, 100,50);
 button4 -> setStyleSheet("background-color:rgb(108, 118, 143)");
 connect(button4, SIGNAL (clicked()), this, SLOT (useVector4()));

 button5 = new QPushButton("Spin right", this);
 button5 -> setGeometry(50,550, 100,50);
 button5 -> setStyleSheet("background-color:rgb(108, 118, 143)");
 connect(button5, SIGNAL (clicked()), this, SLOT (useVector5()));

 label = new QLabel("", this);
 label ->setStyleSheet("background-color:rgb(0, 0, 0)");
 label -> setGeometry(300,50,300,600);
}


//************************************************************************
    MainWindow::~MainWindow(){
     delete ui;
    }
//*************************************************************************
    void MainWindow::useVector0(){
     arm.vctrMovesFun[0]();
     arm.displayMoves(label);}
//*************************************************************************
void MainWindow::useVector1(){
   arm.vctrMovesFun[1]();
   arm.displayMoves(label);
}
//*************************************************************************
void MainWindow::useVector2(){
   arm.vctrMovesFun[2]();
   arm.displayMoves(label);
}
//*************************************************************************
void MainWindow::useVector3(){
   arm.vctrMovesFun[3]();
   arm.displayMoves(label);
}
//*************************************************************************
void MainWindow::useVector4(){
   arm.vctrMovesFun[4]();
   arm.displayMoves(label);
}
//*************************************************************************
void MainWindow::useVector5(){
   arm.vctrMovesFun[5]();
   arm.displayMoves(label);
}

main.cpp: main.cpp:

#include <QApplication>
#include "mainwindow.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    MainWindow w;
    w.show();

    return a.exec();
}

As you can see there is nothing special. 如您所见,没有什么特别的。 My questions: 我的问题:

  1. I don't understand ui in MainWindow class. 我在MainWindow类中不了解ui What is it and how can it be helpful in Qt? 它是什么?对Qt有什么帮助?

  2. When I create vector of pointers to my functions I need to make them static, in another way I can't put them into vector. 当我创建指向函数的指针的向量时,我需要使它们成为静态的,以另一种方式,我不能将它们放入向量中。 Why? 为什么? (class Arm ) (类Arm

  3. Constructor in MainWindow . MainWindow构造方法。 Generally constructor is being called only once when we are creating our object, so why method connect in MainWindow.cpp work for the whole program? 通常,构造函数在创建对象时仅被调用一次,那么为什么MainWindow.cpp connect方法在整个程序中起作用?

  4. As you can see, there is 6 method to use my own function. 如您所见,有6种方法可以使用我自己的函数。 I named them for example as: void useVector0() . 我将它们命名为: void useVector0() I am truly sure that it's very bad to do. 我确实确信这样做非常不好。 There should be one method but if I do something like: 应该有一种方法,但是如果我做类似的事情:

     void MainWindow::useVector(unsigned short k){ arm.vctrMovesFun[k](); arm.displayMoves(label); 

    I can't use it as a slot because signal clicked() has no arguments. 我不能将其用作插槽,因为信号clicked()没有参数。 How to solve it? 怎么解决呢? Overload clicked() method? 重载clicked()方法?

  5. Maybe you have a general opinion about my code so write it. 也许您对我的代码有一般的看法,所以写吧。 I'll be very happy for every words of criticism. 我会为每一个批评的话感到高兴。

As others have already pointed out, your question needs some improvement. 正如其他人已经指出的那样,您的问题需要改进。 I suggest you read How to ask , where you'll find nice guidlines about what can I ask around here and how do I ask a nice question . 建议您阅读“ 如何提问” ,在哪里可以找到关于如何在这里问以及如何问一个好的问题的良好指导

Nonetheless, I'm going to give you a brief answer to your questions, hoping that it will allow you to ask a more specific, new question, if you have one. 尽管如此,我将给您一个简短的答案,希望它可以让您提出一个更具体的新问题(如果有)。


  1. What are .ui files, of a "Qt-Form-Class" good for? 什么是.ui文件,适合“ Qt-Form-Class”?

    Right now you are creating your buttons inside of the MainWindow 's constructor. 现在,您正在MainWindow的构造函数中创建按钮。 That might be okay for simple GUIs, but you have to kind of "guess" the positions of the buttons. 对于简单的GUI来说可能没问题,但是您必须“猜测”按钮的位置。

    If you use the Qt Designer you can create your layouts with the help of some tools. 如果使用Qt Designer ,则可以在某些工具的帮助下创建布局。 Once you've placed some elements with the designer you will be able to access them from code like this: 在设计器中放置了一些元素之后,您将可以从如下代码中访问它们:

     ui->label1->setText("hello World"); 

    You can connect those UI widgets' signal to slots either by using connect() in your code or by using the Designer to add them to the UI file. 您可以通过在代码中使用connect()或通过使用Designer将它们添加到UI文件中,来将这些UI窗口小部件的信号连接到插槽。


  1. How can I create a pointer to a member function? 如何创建指向成员函数的指针?

    http://en.cppreference.com/w/cpp/language/pointer#Pointers_to_member_functions http://en.cppreference.com/w/cpp/language/pointer#Pointers_to_member_functions

  1. Not sure what you're asking here 不知道你在这里问什么

  1. How can I execute different code in a slot, depending on the sender? 如何根据发件人在插槽中执行不同的代码?

    Take a look at QSignalMapper . 看看QSignalMapper

    It will not give you a unsigned short k as you asked for, but a QString depending on which widget emitted the signal. 它不会像您要求的那样给您一个unsigned short k ,而是一个QString具体取决于哪个小部件发出信号。


  1. Could you review my code? 您可以查看我的代码吗?

    Now that's definitely a question for the Code Review Stack Exchange site. 现在,对于Code Review Stack Exchange网站绝对是一个问题。

  1. QMainWindow is basically same as QWidget when used as a (guess what) main window, the noticeable difference is that QWidget expects you to have only 1 window in ur application, while QMainWindow is more about serving as the most important window which will "control" all the rest (like alert message boxes for example). QMainWindow用作(猜测)主窗口时与QWidget基本相同,值得注意的区别是QWidget期望您的应用程序中只有1个窗口,而QMainWindow则更多地是充当“控制”最重要的窗口所有其余的(例如警报消息框)。 you really should use QWidget as the base in most cases unless you are sure you even need QMainWindow. 除非您确定甚至需要QMainWindow,否则在大多数情况下,您实际上应该使用QWidget作为基础。

  2. i am not completely sure about it so please don't count it as a biblical rule, but if i remember correctly: member class functions are not duplicated per object, means every instance of the class calls the one and only address assigned to the function in class creation. 我对此并不完全确定,所以请不要将其视为圣经规则,但如果我没有记错的话:成员类函数不会针对每个对象重复,这意味着该类的每个实例都将调用分配给该函数的唯一地址在课堂创作中。 in other words - they are static. 换句话说-它们是静态的。

  3. notice, that " everywhere " in the program is actually inside the constructor itself. 注意,程序中的“ 无处不在 ”实际上是在构造函数内部。 kek. 极客 most of Qt coding happens in the scope of the main window constructor function upon it's creation. 大多数Qt编码在创建时都发生在主窗口构造函数的范围内。 it is a bit hard to understand if you are used to main() inside main.cpp . 如果您习惯于main.cpp内部的main(),则很难理解。 ofcourse the "connect" method is working anywhere inside the constructor because the constructor is in the same scope as any other method of the class (constructor is a method too afterall) 当然,“连接”方法在构造函数内部的任何地方都可以使用,因为构造函数与该类的其他任何方法都在同一范围内(毕竟构造函数也是一种方法)

  4. indeed there is a better way. 确实有更好的方法。 the new "connect" version of qt5 is taking a reference to both signal and slot functions instead of macros SLOT() and SIGNAL(), means you can fit-in more dynamically and flexibly. qt5的新“连接”版本引用了信号和插槽功能,而不是宏SLOT()和SIGNAL(),这意味着您可以更灵活,更灵活地进行安装。 you shall adopt that new version or at least know about it's existence, as it is awesome. 您应该采用该新版本,或者至少要知道它的存在,因为它很棒。 (you are using qt4 version of connect, which is still supported tho) (您使用的是qt4版本的connect,仍然支持该功能)

  5. unfortunately, TLDR :D you can take it as a critics. 不幸的是,您可以将TLDR:D视为批评家。 good luck in your project m9 在您的项目中祝您好运m9

I don't understand ui in MainWindow class. 我在MainWindow类中不了解ui。 What is it and how can it be helpful in Qt? 它是什么?对Qt有什么帮助?

Currently you're creating your GUI in code. 当前,您正在用代码创建GUI。 However, there are applications (like Qt Creator's "Design" mode) that will write the code that creates your GUI for you. 但是,有些应用程序(例如Qt Creator的“设计”模式)将编写为您创建GUI的代码。 The problem with that is that, if you then edit that code, Qt Creator will have a very hard time reconciling your modifications with any changes it wants to make. 问题在于,如果您随后编辑该代码,Qt Creator将很难协调您的修改与要进行的任何更改。

To avoid the issue, you use the object in the ui instance variable. 为避免此问题,请在ui实例变量中使用该对象。 That object is what Qt Creator generates, and you don't touch that code. 该对象是Qt Creator生成的,您无需触摸该代码。 Instead, all your code goes into your MainWindow . 取而代之的是,所有代码进入你的MainWindow

When I create vector of pointers to my functions I need to make them static, in another way I can't put them into vector. 当我创建指向函数的指针的向量时,我需要使它们成为静态的,以另一种方式,我不能将它们放入向量中。 Why? 为什么? (class Arm) (手臂类)

static functions are standalone functions. 静态函数是独立函数。 They don't have an object associated with them. 他们没有与之关联的对象。 Member functions (non-static functions in an object) on the other hand, have a "this". 另一方面,成员函数(对象中的非静态函数)具有“ this”。 So, to call a standalone function, you just call MyFunction( 1 ) or whatever, whereas to call a member function, you need to tell it which object's member function you want to call ( myObject->MyMemberFunction( 1 ) ). 因此,要调用独立函数,只需调用MyFunction( 1 )或其他任何方法,而要调用成员函数,则需要告诉它要调用哪个对象的成员函数( myObject->MyMemberFunction( 1 ) )。

Your is defined to hold pointers to standalone functions, so doesn't have any room to store the object pointers to go with a member function. 您的定义是保留指向独立函数的指针,因此没有空间来存储对象指针与成员函数一起使用。

If you want to learn more about pointers to member functions , look up that topic in any good C++ textbook. 如果您想了解有关成员函数指针的更多信息,请在任何优秀的C ++教科书中查找该主题。 That said, Qt hides C++'s pointers to member functions behind slots and signals. 也就是说,Qt将C ++的指向成员函数的指针隐藏在插槽和信号后。 So you might just want to not keep an array and instead define an array of those. 因此,您可能只想不保留一个数组,而是定义一个数组。

Constructor in MainWindow. MainWindow中的构造方法。 Generally constructor is being called only once when we are creating our object, so why method connect in MainWindow.cpp work for the whole program? 通常,构造函数在创建对象时仅被调用一次,那么为什么MainWindow.cpp中的connect方法在整个程序中起作用?

There is only one MainWindow object in your project, and it is created at the start of main() and only goes away once main() exits. 您的项目中只有一个MainWindow对象,它是在main()的开始处创建的,并且仅在main()退出后才消失。 So it lives just as long as your entire application. 因此,它的寿命与整个应用程序一样长。

As you can see, there is 6 method to use my own function. 如您所见,有6种方法可以使用我自己的函数。 I named them for example as: void useVector0(). 我将它们命名为:void useVector0()。 I am truly sure that it's very bad to do. 我确实确信这样做非常不好。 (...) I can't use it as a slot because signal clicked() has no arguments. (...)我不能将其用作插槽,因为信号clicked()没有参数。

I think you want QSignalMapper for that: Passing an argument to a slot 我认为您需要使用QSignalMapper: 将参数传递到插槽

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM