This is inside a Menu class. The problem is addAction. This works, but there is no connection to slot:
QMenu* menu2 = new QMenu("Test");
menu2->addAction("Test");
When I do this:
QMenu* menu2 = new QMenu("Test");
menu2->addAction("Test", Menu, test);
I get compiler error: "error: expected primary-expression before ',' token"
I mean to call the test() function in the Menu class. What am I doing wrong?
Well, the error comes from passing Menu as an argument. You say Menu is a class, and classes are not expressions on themselves.
If you need to call test on an instance of Menu, where Menu is not a derivate from QObject (ie. no slots available), then you can just create a slot in the widget that contains the QMenu itself (probably a QMainWindow), and implement the call in there!
Edit: to add an example.
class MainWindow : public QMainWindow {
Q_OBJECT
// Usual declarations...
private slots:
void myCustomSlot();
};
Now, say that you're populating the main window inside its constructor:
MainWindow::MainWindow(...) {
// Some initialization code
QMenu *menu2 = new QMenu("Test");
menu2->addAction("Test", this, SLOT(myCustomSlot));
// Some more initialization code
}
// ...
void MainWindow::myCustomSlot() {
instanceOfMenu->test();
}
Of course, if you're creating the menu outside that class, you'd need to make the slot public, but that's another issue
Related
My QGraphicsScene subclass WorkspaceScene contains a variable for each action that it later uses inside the context menu. I have a function that sets up the actions and adds the shortcuts (which is called in the constructor of the class), and then I have a function that creates the context menu, which is called in the contextMenuEvent function I reimplemented.
Here's some relevant code:
// Constructor
WorkspaceScene::WorkspaceScene()
{
_setUpActions();
}
// ContextMenuEvent
void WorkspaceScene::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
_setUpItemMenu();
_itemContextMenu.exec(event->screenPos());
}
void WorkspaceScene::_setUpActions()
{
deleteAction = new QAction("Delete");
deleteAction->setShortcut(QKeySequence::Delete); // This should add the shortcut
connect(deleteAction, &QAction::triggered, this, &WorkspaceScene::deleteItemSlot);
}
void WorkspaceScene::_setUpItemMenu()
{
_itemContextMenu.clear();
_itemContextMenu.addAction(deleteAction);
}
This successfully sets up the actions and they work inside the context menu but the shortcut doesn't seem to work. What's the correct way of doing this?
I solved it by adding the QAction to the QGraphicsView parent of the QGraphicsScene.
I've made a class named MyWindow which inherits from QWidget to create a window. Here is the content of mywindow.h:
class MyWindow: public QWidget{
public:
MyWindow(QString title,QString icon,int w = 600,int h = 400);
int getWidth() const;
int getHeight() const;
public slots:
void openDialogBox(QString title,QString message);
private:
int m_width;
int m_height;
};
There is a openDialogBox slot which takes the title and the message of the dialog box as arguments.
I've made a menu bar which basically looks like this:
MyWindow myWindow("Example window",QCoreApplication::applicationDirPath() + "/icon.png");
QMenuBar menuBar(&myWindow);
menuBar.setGeometry(0,0,myWindow.getWidth(),menuBar.geometry().height());
QMenu *fileMenu = new QMenu("&File");
QAction *fileMenu_open = fileMenu->addAction("&Open");
MyWindow::connect(fileMenu_open,&QAction::triggered,&myWindow,&MyWindow::openDialogBox);
In the last line, I would like to send arguments to the slot &MyWindow::openDialogBox. I tried to do:
MyWindow::connect(fileMenu_open,&QAction::triggered,&myWindow,&MyWindow::openDialogBox("Title","Hello, this is a message"));
but it didn't work (I don't need you to explain why it didn't work, I already know why). How to do this properly so that it works?
Since you are using the New Signal Slot Syntax, I would suggest using a c++11 lambda instead of a slot, and call the desired function inside your slot, here is how your connect call would look like:
QObject::connect(fileMenu_open, &QAction::triggered, &myWindow, [&myWindow](){
myWindow.openDialogBox("Title","Hello, this is a message");
});
Note that openDialogBox is not required to be a slot this way, it can be any normal function.
If your compiler does not support C++11 lambda expression, you might have to declare a slot that does not take any argument, and connect to that slot. And inside that slot call your function with the desired arguments. . .
Use lambdas
QObject::connect(fileMenu_open, &QAction::triggered, &myWindow, [QWeakPointer<MyWindow> weakWindow = myWindow]()
{
weakWindow->openDialogBox("Title","Hello, this is a message");
});
QWeakPointer is used in case your class is moved, so the "old" myWindow is a dangling pointer
If your class won't be moved, just capture myWindow.
Note that my code needs C++14 to declare a variable in the lambda capture
I have a small problem. I want run function in MainWindow from AnotherWindow. I can't set connect() for it.
Main class: MainWindow
Other form: AnotherWindow
Function in main class: setVariable(QString)
Function in other form: btnClicked()
I have now connected button signal clicked():
// In AnotherWindow.cpp
connect(ui->btnOK, SIGNAL(clicked()), this, SLOT(btnOkClicked()));
// Function in same file
void interfaceWindow::btnOkClicked() {
/* Some actions - emit signal? */
this->close();
}
btnOkClicked() are declared as private slot.
// In MainWindow.cpp
void MainWindow::setVariable(QString _var) {
this->var = _var;
}
setVariable(QString) are declared as public slot.
How I can send variable from AnotherForm (from btnOkClicked() function) to MainWindow (setVariable(QString) function) ? How and where I must send signal and make connection?
I readed about signals and slots, but my code don't work - I don't paste it here because it's terrible :)
Any help for Qt newbie?
You need to have an reference of AnotherWindow in MainWindow OR vice versa. Then you need the following things:
// AnotherWindow.h
signals:
void buttonOkClickedSignal(QString var);
// AnotherWindow.cpp
void interfaceWindow::btnOkClicked() {
emit buttonOkClickedSignal("The button got clicked!");
this->close();
}
Next step varies based on whether MainWindow has reference to AnotherWindow or vice versa. You can either:
// AnotherWindow.cpp
connect(this, SIGNAL(buttonOkClickedSignal(QString), &mainWindow, SLOT(setVariable(QString)));
or:
// MainWindow.cpp
connect(&anotherWindow, SIGNAL(buttonOkClickedSignal(QString), this, (SLOT(setVariable(QString)));
If you are invoking the slot through signal it shouldn't matter whether it's private or public (see Qt Documentation).
Hope this helps.
I'm not entirely sure I understand your question, but let me try.
You want to be able to fire a slot in another class. There are a few ways you can do that.
Declare one as a friend class to the other. Then they can see the protected and private variables/memebers
It is possible to make slots static so you can call them without a class object.
For example,
class MainWindow {
private slot:
void setVariable(QString);
}
class AnotherWindow {
friend class MainWindow;
MainWindow *window;
public:
AnotherWindow() {
connect(this, SIGNAL(fire(QString)), window, SLOT(setVariable(QString)));
}
signals:
void fire(QString);
public slots:
void onButtonClicked() {
emit fire(QString);
}
}
The previous is pseudocode so don't expect it to compile. I think this is what you want. Basically since your slot is private on MainWindow you need to make it a friend. To connect, it needs to be a member. Then when the onButtonClicked slot is evoked, then it fire()s the setVarialbe() slot.
Here is a simple code for your another window:
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget * parent = 0)
{
okBtn = new QPushButton ("I am Ok!");
MyData = "";
connect(okBtn ,SIGNAL(clicked()),this,SLOT(OnOk()));
}
~MyWidget();
private:
QString MyData;
QPushButton * okBtn;
//something that modify string MyData
signals:
void MyDataSignal(QString);
//Internal slot that emits signal with proper data
private slots:
void OnOk()
{
if(MyData!="")
{
emit MyDataSignal(MyData);
}
}
};
Now in MainWindow create an object of MyWidget (suppose myWid)and connect it to slot
connect(myWid, SIGNAL(MyDataSignal(QString)),this,SLOT(OnMyWidOkClicked(QString)));
the signal will pass string to slot.
While making signals and slots keep in mind following points:
To connect a signal to a slot (or to another signal), they must have the same parameter
Parameters should be in the same order in both signal and slot.
if a signal has more parameters than the slot it is connected to, the additional parameters are simply ignored but opposite is not possible.
If you will connect a signal that have unmatched parameters to slot then no compile time error will occur but at run time command window will show a warning that signal/slot/connection does not exist.
Here's a simple code that creates a button and assigns a onclick handler:
auto btn = new QPushButton("CLICK ME");
connect(btn, SIGNAL(clicked()), this, SLOT(btn_Click()));
private slots:
void btn_Click() {
alert("clicked!");
}
It works as it should if called in the main window class. However when I try to do this in a child window, clicking the button does nothing. The child window is shown like this:
auto settingsWindow = new SettingsWindow();
settingsWindow->show();
I guess it's somehow connected with the receiver object which is now a different window. But how can I make it work?
In order to be able to declare signals/slots in your own class you should include Q_OBJECT directive in your class:
class SettingsWindow {
Q_OBJECT
...
};
You should add a MACRO in class SettingsWindow to enable singal receiving.
Add "Q_OBJECT" like the following.
class MainWidget : public QWidget
{
Q_OBJECT
public:
MainWidget();
....
//clposter.h
class CLPoster : public QMainWindow
{
Q_OBJECT
public:
CLPoster();
private slots:
QWidget createCentralWidget();
void createActions();
void createMenu();
void createStatusBar();
void loadSavedPosts();
};
//clposter.cpp
CLPoster::CLPoster()
{
setWindowTitle("Craigslist Poster");
QWidget mainWidget = createCentralWidget();
setCentralWidget(mainWidget);
// createActions();
// createMenu();
// createStatusBar();
// loadSavedPosts();
// checkForActionsNeeded(); //May want to break up into more functions
}
The error I'm getting is this:
/usr/include/qt4/QtGui/qwidget.h:: In constructor ‘CLPoster::CLPoster()’:
/usr/include/qt4/QtGui/qwidget.h:787: error: ‘QWidget::QWidget(const QWidget&)’ is private
/home/brett/projects/CLPoster/CLPoster-build-desktop/../CLPoster/clposter.cpp:9: error: within this context
/home/brett/projects/CLPoster/CLPoster-build-desktop/../CLPoster/clposter.cpp:10: error: no matching function for call to ‘CLPoster::setCentralWidget(QWidget&)’
/usr/include/qt4/QtGui/qmainwindow.h:141: candidates are: void QMainWindow::setCentralWidget(QWidget*)
I'm having trouble interpreting the error message. It says there is no matching function call, but it should be inheriting it from QMainWindow. It could just be a lack of understanding C++ more so than QT, first time I've used it, but dunno. Thanks for the help.
All QWidget items must be allocated in the free-store (new) since they all have to have "parents". In Qt a parent will delete its children (with delete). This is why any function returning, accepting, whatever a widget is going to do so on a pointer to a widget, not the widget itself; you need to do the same.
The setCentralWidget function expects that you are sending a pointer to a QWidget (QWidget*), whereas you are trying to send the actual object (or a reference to the object, QWidget&, as implied by the compiler error) in your code. If you create your central widget as a pointer (change the member function to QWidget* createCentralWidget()) and pass the pointer to the setCentralWidget function you should be good to go.
e.g.
QWidget* CLPoster::createCentralWidget()
{
QWidget* w = new QWidget;
// Do stuff..
return w;
}
Then in your constructor, you can just call setCentralWidget(createCentralWidget()). The QMainWindow destructor will ensure that your central widget is deleted.
Don't you need to allocate the Widget on the heap and pass a pointer to setCentralWidget()