QToolButton should have another icon than the default action - qt

When using a QToolButton and the setDefaultAction(myAction) method, it will get the default actions properties
Reference:
If a tool button has a default action, the action defines the button's
properties like text, icon, tool tip, etc.
So I try to overwrite the icon, calling setIcon on the QToolButton.
myAction.setIcon(...);
myToolButton->setDefaultAction(myAction);
myToolButton->setIcon(...);
But it myToolButton still has the Icon of myAction.
Is there a way to hold the default action but overwrite it's icon, only for the QToolButton, not for the action itself? In otherwords: How can the QToolButtons have different properties than its default action?

If you take a look at the source for QToolButton::setDefaultAction(QAction* action), it uses setIcon(action->icon()) to set the icon from the action you give it. You can override that icon manually by calling setIcon with your desired separate icon after you call setDefaultAction.
Edit:
Here's a quick example you can try. Maybe you can compare it to what you're currently doing or post an example of your own?
MainWindow.cpp
#include "MainWindow.hpp"
#include <QAction>
#include <QToolButton>
MainWindow::MainWindow(QWidget* parent) :
QMainWindow(parent) {
QAction* action = new QAction(QIcon(QStringLiteral("original.jpg")), QStringLiteral("Test Action"), this);
QToolButton* toolButton = new QToolButton(this);
toolButton->setDefaultAction(action);
toolButton->setIcon(QIcon(QStringLiteral("new.jpg")));
}
MainWindow.hpp
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QWidget>
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget* parent = nullptr);
};
#endif // MAINWINDOW_H
main.cpp
#include "MainWindow.hpp"
#include <QApplication>
int main(int argc, char* argv[]) {
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}

QToolButton icon will reset to action icon when action changed.
We need re-override code like this;
connect(toolButton, &QAction::changed, [=](){
toolButton->setIcon(QIcon(QStringLiteral("new.jpg")));
});

Related

How to use TAB Key to focus one of two qpushbutton

In a widget I put two QPushButton (let's say "OK" at left and "EXIT" at right).
They regularly work when I press them using the mouse.
Suppose I want to switch from one to the other using TAB key: is it possible?
And how can do this?
On some platforms, keyboard focus navigation among buttons is a default behavior, but on some it isn't.
If you wish keyboard navigation on all platforms, the buttons should have a Qt::StrongFocus policy set on them. Note that the shortcut used to trigger the buttons is also platform-specific. E.g. on OS X you'd use Space.
#include <QtWidgets>
int main(int argc, char ** argv) {
QApplication app{argc, argv};
QWidget w;
QVBoxLayout layout{&w};
// Individual Buttons
QPushButton p1{"button1"}, p2{"button2"};
for (auto p : {&p1, &p2}) {
layout.addWidget(p);
p->setFocusPolicy(Qt::StrongFocus);
}
// A button box
QDialogButtonBox box;
for (auto text : {"button3", "button4"})
box.addButton(text, QDialogButtonBox::NoRole)->setFocusPolicy(Qt::StrongFocus);
layout.addWidget(&box);
w.show();
return app.exec();
}
I tried it out on KDE/Ubuntu. It works automatically.
main.cpp
#include <QApplication>
#include "mainwindow.hpp"
int main(int argc, char** args) {
QApplication app(argc, args);
MainWindow m;
m.show();
return app.exec();
}
mainwindow.hpp
#ifndef MAINWINDOW_HPP
#define MAINWINDOW_HPP
#include <QMainWindow>
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow();
};
#endif // MAINWINDOW_HPP
mainwindow.cpp
#include "mainwindow.hpp"
#include <QPushButton>
#include <QVBoxLayout>
MainWindow::MainWindow() : QMainWindow() {
auto* w = new QWidget;
auto* l = new QVBoxLayout;
auto* p1 = new QPushButton("ok");
auto* p2 = new QPushButton("exit");
l->addWidget(p1);
l->addWidget(p2);
w->setLayout(l);
setCentralWidget(w);
}
a.pro
TEMPLATE = app
TARGET = a
INCLUDEPATH += .
QT += widgets
HEADERS += mainwindow.hpp
SOURCES += main.cpp mainwindow.cpp
QMAKE_CXXFLAGS += -std=c++14
Edit: Apparently the buttons switch focus, but pressing enter does nothing. I guess you have to use focus-related mechanics (search for "focus" in the QWidget documentation) and implement it yourself. Or have a look at QDialog (as a replacement for QMainWindow in my example). It should have some meaningful default behavior for the enter and escape buttons.
Side note: Maybe you rather want to use the QDialogButtonBox for ok- and exit-buttons in your project. It's the cross-platform way of displaying OK/Cancel/Accept/Reject/... buttons because their arrangement differs between platforms. And this class can help you with that.
It is easier than all that code. Just use setFocusPolicy with Tabfocus on both buttons like this:
yourButtonOk->setFocusPolicy(Qt::TabFocus);
yourButtonExit->setFocusPolicy(Qt::TabFocus);

Dynamically adding widgets to gridLayout Qt

I am having a bit of difficulty with some code. I am super rather new to Qt so it is entirely possible that I am simply ignorant to the problem I am having.
Basically, I am blocking out a program so that I can add the specifics of it later. I want to be able to create a grid of buttons, and when one of those buttons is pressed, another shape to replace it.
I am able to make my button grid, have it be scrollable, and have the button call it its position on the grid when pressed. However, when I try and use those coordinates to add another button to the grid, Qt crashes.
Here's my code so far:
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <cmath>
#include <QLabel>
#include <QMainWindow>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QApplication>
#include <QPushButton>
#include <QScrollArea>
#include <QDebug>
#include <QString>
#include <QSignalMapper>
#include <QStringList>
#include <QLayoutItem>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
populateViewGrid(); //I wanted to see if I could add in a scrollbar
//from outside the main window. Could this be causing
// the issue?
}
void MainWindow::populateViewGrid()
{
QScrollArea*scrollArea = new QScrollArea(this);
QWidget*central = new QWidget(this);
QGridLayout*gridLayout = new QGridLayout(central);
QSignalMapper *signalMapper = new QSignalMapper(central);
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
QString position= QString("%1,%2").arg(i).arg(j);
QPushButton* button = new QPushButton("addTrack",central);
gridLayout->addWidget(button, i, j);
connect(button, SIGNAL(clicked()),signalMapper, SLOT(map()));
signalMapper->setMapping(button, position);
}
}
connect(signalMapper, SIGNAL(mapped(QString)),this, SLOT(addTrack(QString )));
central->setLayout(gridLayout);
scrollArea->setWidget(central);
setCentralWidget(scrollArea);
}
void MainWindow::addTrack(QString position)
{
QStringList query = position.split(",");
int x;
x=query.at(0).toInt();
int y;
y=query.at(1).toInt() ;
QPushButton *Ifthisworks=new QPushButton(this);
//This first line is where is crashes. I know this due to having the code
//laced with qDebugs. From all of my google searches and such, it seems that
// something simple should be wrong and I can't find it.
QLayoutItem * existingitem = gridLayout->itemAtPosition(x, y);
if(existingitem) {
gridLayout->removeItem(existingitem);
delete existingitem;
}
// before I included the above to remove the button from the grid point, the
//program would crash here.
gridLayout->addWidget(Ifthisworks, x, y);
}
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();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <cmath>
#include <QLabel>
#include <QMainWindow>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QApplication>
#include <QPushButton>
#include <QMainWindow>
#include <QScrollArea>
#include <QSignalMapper>
#include <QHash>
//unrelated question, do I need the above in my code? I know not all of them
//used, but do I need includes in this file as well?
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void populateViewGrid();
QGridLayout *gridLayout;
public slots:
void addTrack(QString);
private:
QScrollArea*scrollArea;
QWidget * central;
QPushButton *Ifthisworks;
QSignalMapper *signalMapper;
QPushButton *clockViews;
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
If you could help me understand how to not make Qt crash there and also add a button, that would be fantastic =)
So some background real quick incase you are looking at my code and are scratching your head. I'm a mechanical engineer who should have probably been an electrical or computer engineer and knows enough about coding to get myself into these kinds of messes. For the most part, I searched for what I wanted Qt to do and hacked it all together to hopefully make it work. Any bit of deeper understanding you can share would be more than welcome.
Thank you for your time.
You are initializing a local variable called gridLayout in your MainWindow::populateViewGrid() method:
QGridLayout*gridLayout = new QGridLayout(central);
Then in your MainWindow::addTrack(QString position) method, you are trying to access the member variable called gridLayout which is never initialized.
To fix this, simply initialize the member variable instead of creating a local variable in your MainWindow::populateViewGrid() method:
gridLayout = new QGridLayout(central);
You are doing the same mistake with your other member variables as well. Fix them the same way.
I would go for a different implementation.
Move gridlayout, signalmapper,... to be class members. I personally like also to keep a list of my widgets QList<QPushButton*> for manually deleting or keeping a button cache.
Make the signalmapper to map to index in list or QWidget*. For the example i`ll go with the QWidget* pointer.
QPushButton *newButton = new QPushButton("The new Thing");
QPushButton *oldButton = static_cast<QPushButton*>(widgetPointer);
gridLayout->replaceWidget(oldButton ,newButton);
buttonList->takeAt(buttonList->indexOf(oldButton))->deleteLater()); //if you keep a list..
buttonList->insert(buttonList->indexOf(oldButton),newButton);

Bogus widget in Qt Creator

I'm a Qt newbie, working in Qt Creator 3.1.2 (Ubuntu Linux), Qt 5.3.1.
My program has a form with a button (pushButton) which changes the value of a text field (plainTextEdit) on being pressed. Both pushButton and plainTextEdit have been added in graphical mode. Connection between the button and its slot (on_pushButton_clicked()) has been set up via the graphical interface too.
The problem is, the program produces a bogus plainTextEdit, i.e. a different one, in the upper left corner, where the output goes to, while the "main" one stays clean. The question hence is, how I can avoid it? In general, how should I connect graphical widgets and their counterparts in the code? Here is my program:
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPushButton>
#include <QPlainTextEdit>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
QPushButton *pushButton;
QPlainTextEdit *plainTextEdit;
};
#endif // MAINWINDOW_H
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"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
plainTextEdit = new QPlainTextEdit(this);
// whenever I remove the previous line, I get SIGSEGV
setWindowTitle(tr("My test app..."));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
plainTextEdit->setPlainText("Some text here");
}
It's the widget you're creating in your constructor that is "bogus". The widgets you created in the forms editor belong to the Ui::MainWindow, you must not re-create them in your main window.
Remove this from your MainWindow:
QPushButton *pushButton;
QPlainTextEdit *plainTextEdit;
Remove the widget creation from the constructor:
plainTextEdit = new QPlainTextEdit(this);
Change your on_pushButtonClicked member to:
ui->plainTextEdit->setPlainText("Some text here");

SLOT rejected(), accepted() in QMainWindow

I am a newbie in Qt-programming. I have read a book about GUI-programming with Qt. I have an trouble in creating a dialog. Here is sample code:
// gotocell.h
#ifndef GOTOCELL_H
#define GOTOCELL_H
#include <QDialog>
#include <QtWidgets>
#include "ui_gotocell.h"
class GoToCellDialog : public QDialog, public Ui::GoToCellDialog
{
Q_OBJECT
public:
GoToCellDialog (QWidget *parent = 0);
private slots:
void on_lineEdit_textChanged();
};
#endif // GOTOCELL_H
// gotocell.cpp
#include <QtWidgets>
#include "gotocell.h"
#include <QtWidgets>
GoToCellDialog::GoToCellDialog (QWidget *parent):
QDialog (parent)
{
setupUi(this);
QRegExp regExp ("[A-Za-z][1-9][0-9]{0,2}");
lineEdit->setValidator(new QRegExpValidator(regExp, this));
connect (okButton, SIGNAL(clicked()), this, SLOT(accept()));
connect (cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
}
void GoToCellDialog::on_lineEdit_textChanged()
{
okButton->setEnabled(lineEdit->hasAcceptableInput());
}
// main.cpp
#include "gotocell.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
GoToCellDialog *dialog = new GoToCellDialog;
dialog->show();
return a.exec();
}
but when I compiled, there is an error: no known conversion for argument 1 from 'GoToCellDialog* const' to 'QMainWindow*'at setupUi() function. I think because the designer in Qt Creator created a QMainWindow, not a QDialog. So I changed GoToCellDialog class to QMainWindow. But there is no slots whose name is "accepted", "rejected" in QMainWindow. Can anyone help me?
If you want to display a Dialog as main window you have two choices:
1. make the whole main window QDialog based
2. design the Dialog separately and set it as the main windows central Widget (QMainWindow->setCentralWidget()).
In both cases you still have the problem what semantics you give to the OK and Cancel buttons. Generally it may be a better idea to consider what the main window of the application should contain, and design the dialogs later.

How to click a button in a out-of-focus widget without changing the current focus to it

I am trying to implement a input method with Qt Embedded.
There is a lookup table for choosing the candidate words for typing. "text input area" to the "lookup table" and the selected word cannot be sent to the "text input area".
Dose anyone have any idea to solve this problem? Thanks~
Here I give a simple example:
main.cpp
#include "InputWidget.h"
#include "ButtonWidget.h"
#include <QApplication>
int main(int argc,char *argv[])
{
QApplication app(argc,argv);
InputWidget *inputWidget=new InputWidget();
ButtonWidget *buttonWidget=new ButtonWidget();
inputWidget->show();
buttonWidget->show();
int ref=app.exec();
inputWidget->deleteLater();
buttonWidget->deleteLater();
return ref;
}
InputWidget.h
#include <QWidget>
#include <QPlainTextEdit>
#ifndef _InputWidget_H_
#define _InputWidget_H_
class InputWidget:public QWidget
{
Q_OBJECT
public:
InputWidget(QWidget *parent=0);
private:
QPlainTextEdit *inputArea;
};
#endif
InputWidget.cpp
#include "InputWidget.h"
#include <QPushButton>
#include <QVBoxLayout>
InputWidget::InputWidget(QWidget *parent):QWidget(parent)
{
//input area setup
inputArea=new QPlainTextEdit(this);
//main layout
QVBoxLayout *mainLayout=new QVBoxLayout(this);
mainLayout->setContentsMargins(1,4,1,1);
mainLayout->addWidget(inputArea);
setLayout(mainLayout);
}
ButtonWidget.h
#include <QWidget>
#include <QPushButton>
#ifndef _ButtonWidget_H_
#define _ButtonWidget_H_
class ButtonWidget:public QWidget
{
Q_OBJECT
public:
ButtonWidget(QWidget *parent=0);
private:
QPushButton *selectedBtn;
public slots:
void changeBtnText();
};
#endif
ButtonWidget.cpp
#include "ButtonWidget.h"
#include <QPushButton>
#include <QVBoxLayout>
ButtonWidget::ButtonWidget(QWidget *parent):QWidget(parent)
{
//selectedBtn setup
selectedBtn=new QPushButton(tr("Click Me!!"),this);
connect(selectedBtn,SIGNAL(clicked()),this,SLOT(changeBtnText()));
//main layout
QVBoxLayout *mainLayout=new QVBoxLayout(this);
mainLayout->setContentsMargins(1,4,1,1);
mainLayout->addWidget(selectedBtn);
setLayout(mainLayout);
}
void
ButtonWidget::changeBtnText()
{
selectedBtn->setText("I am clicked :)");
}
Those codes would generate a widget which has a PlainTextEdit "inputArea" and a widget which has a PushButton "selectedBtn".
First, I input some words in the "inputArea". The current foucs is on "inputArea" in the InputWidget.
But when I move mouse to ButtonWidget and click the "selectedBtn", the foucs is changed to "selectedBtn" in the ButtonWidget.
How do I click the "selectedBtn" but still keep the foucs on "inputArea"? Thanks~
Just like my comment described in laura's answer, InputWidget and ButtonWidget may have no identical parent and I cannot use QWidget's "setFocus" slot to change the current focus between them.
First of all, you will need to make the two widgets know about each other. Once you have done that (by setting the text widget into the button widget or by adding them both to the same parent widget), you can try to see if QWidget's setFocus slot can help you (look at the other slots too, some might be useful for this).
Perhaps implement something like this, in the ButtonWidget:
(in the header) declare a signal foo()
(in the constructor) connect button widget's foo signal to InputWidget's setFocus slot
(in the changeBtnText) after you've done everything you wanted, emit foo()
Note though that setFocus works if the window is active.
You might be able to get what you want by playing with the focusPolicy for your widget. Pay attention to the Qt::NoFocus option. I don't think it prevents mouse clicks on your widget, but you'll want to test to be sure.
Thank laura and cjhuitt, your responses give me a big hint to solve my question.
Because InputWidget and ButtonWidget are two independent widgets, if we want to deal with the focus issue between them, we need a "global" control, i.e., use QApplication to do the focus job.
The key point is using QApplication's "focusChanged" slot and QWidget's "activateWindow". The following is my modification.
main.cpp
#include "InputWidget.h"
#include "ButtonWidget.h"
#include <QApplication>
int main(int argc,char *argv[])
{
QApplication app(argc,argv);
InputWidget *inputWidget=new InputWidget();
ButtonWidget *buttonWidget=new ButtonWidget(0,&app);
inputWidget->show();
buttonWidget->show();
int ref=app.exec();
inputWidget->deleteLater();
buttonWidget->deleteLater();
return ref;
}
ButtonWidget.h
#include <QWidget>
#include <QPushButton>
#include <QApplication>
#ifndef _ButtonWidget_H_
#define _ButtonWidget_H_
class ButtonWidget:public QWidget
{
Q_OBJECT
public:
ButtonWidget(QWidget *parent=0,QApplication *app=0);
private:
QPushButton *selectedBtn;
public slots:
void changeBtnText();
void changeFocus(QWidget *oldWidget,QWidget *curWidget);
};
#endif
ButtonWidget.cpp
#include "ButtonWidget.h"
#include <QPushButton>
#include <QVBoxLayout>
ButtonWidget::ButtonWidget(QWidget *parent,QApplication *app):QWidget(parent)
{
//selectedBtn setup
selectedBtn=new QPushButton(tr("Click Me!!"),this);
connect(selectedBtn,SIGNAL(clicked()),this,SLOT(changeBtnText()));
//main layout
QVBoxLayout *mainLayout=new QVBoxLayout(this);
mainLayout->setContentsMargins(1,4,1,1);
mainLayout->addWidget(selectedBtn);
setLayout(mainLayout);
//deal with focus
connect(app,SIGNAL(focusChanged(QWidget*,QWidget*)),this,SLOT(changeFocus(QWidget*,QWidget*)));
}
void
ButtonWidget::changeBtnText()
{
selectedBtn->setText("I am clicked :)");
}
void
ButtonWidget::changeFocus(QWidget *oldWidget,QWidget *curWidget)
{
if(oldWidget && curWidget==this)
oldWidget->activateWindow();
}
InputWidget.cpp and InputWidget are not modified.
This solution can work in this example, but I am not sure that it can work in two independent Qt programs(they have their own QApplication), especially in Qt Embedded environment. I would continue doing some tests on it. If there are any results, I would also post them here.
Thank for this discussion, I have learned a lot and thank you all again!!

Resources