How do I add a custom ApplicationShortcut in Qt - c++

I have the following code:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
mUi(new Ui::MainWindow)
{
mUi->setupUi(this);
this->setFixedSize(this->width(), this->height());
StyleUi();
auto closeAct = new QAction(this);
closeAct->setShortcut(QKeySequence("Ctrl+O"));
connect(closeAct, SIGNAL(activated()), this, SLOT(close()));
closeAct->setShortcutContext(Qt::ApplicationShortcut);
addAction(closeAct);
}
The last 5 lines define a QAction with a shortcut created from the sequence Ctrl+O, connects the QAction the the slot Close(). I've found this example here on stackoverflow and several other documentation sites describe what I want to do as such. However, I am not getting anywhere with this. My program doesn't close when I hit Ctrl+O. Any suggestions on where I am doing something wrong?

You can create it by using the multiple arguments constructor for QKeySequence.
like this:
QShortcut *shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_O), this);
shortcut->setContext(Qt::ApplicationShortcut);
And try this to get QShortcut signal activated:
connect(shortcut, &QShortcut::activated, this, &MainApp::activeShortcut);
void MainApp::activeShortcut()
{
this->close();
}
This is a sample project for your question on github download here.

Related

How to clear a label in qt creator

this is the first time i write in this site, I'm trying approach me at Qt-creator but I've a problem:
I want to delete the text of the label when the user click a button, i've tried some solution but without success
this is the code:
struct finestra{
float costo;
int altezza;
int larghezza;
QString text;
QString costoStr;
};
float Totale=0;
finestra vet[21];
int i=1;
//SOME CODE
Totale+=vet[i].costo;
vet[i].costoStr = QString::number(vet[i].costo);
vet[i].text = vet[i-1].text + "Finestra ad un anta bianca <br>" + "€" + vet[i].costoStr +"<br>";
ui->TotaleFinestre->setText(QString(vet[i].text));
i++;
I've tried with this function:
void preventivi::on_pushButton_clicked()
{
ui->TotaleFinestre->clear();
}
if someone know how to do please answer,
thanks to all and sorry for my bad english.
Maybe you should try
void preventivi::on_pushButton_clicked()
{
ui->TotaleFinestre->setText("");
}
As QLabel define the slot void QLabel::clear(), you can also just connect this slot with the clicked() signal that will be emitted after a click on your pushButton, using the QObject::connect method :
QObject::connect(pointer_to_your_pushButton, SIGNAL(clicked()), pointer_to_your_label, SLOT(clear()));
EDIT : Here is a small example
The UI is a QWidget that has a QLabel and a QPushButton. I did that with Qt Designer but it doesn't matter here.
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
QObject::connect(ui->pushButton, SIGNAL(clicked()), ui->label, SLOT(clear()));
}
Widget::~Widget()
{
delete ui;
}
You can even do that using "Edit Signals/Slots" inside Qt Designer and make the signal/slot connection between your widgets. ( you won't need to manually call the previous QObject::connect, as it will be done automatically inside the Ui_Widget class, generated by the uic)
Or you can do all without Qt Designer, it's up to you.
Hope this helps.

Qt push button is calling 2 slots and I only need one

I need to call a 2 functions with different buttons
I have this code:
signalMapperSelections = new QSignalMapper();
QPushButton *selected_type_button = new QPushButton();
selected_type_button->setObjectName("selected_type_button");
selected_type_button->setText(get_selected_type().replace(" ", "\n"));
selected_type_button->setMinimumHeight(80);
selected_type_button->setMinimumWidth(80);
selected_type_button->setMaximumHeight(80);
selected_type_button->setMaximumWidth(80);
selected_type_button->setStyleSheet(style_toolbutton);
ui->verticalLayout_selections->addWidget(selected_type_button);
connect(selected_type_button, SIGNAL(clicked()), signalMapperSelections, SLOT(map()));
signalMapperSelections->setMapping(selected_type_button, get_selected_type());
connect(signalMapperSelections, SIGNAL(mapped(QString)), this, SLOT(show_brands(QString)));
QPushButton *selected_brand_button = new QPushButton();
selected_brand_button->setObjectName("selected_brand_button");
selected_brand_button->setText(get_selected_brand().replace(" ", "\n"));
selected_brand_button->setMinimumHeight(80);
selected_brand_button->setMinimumWidth(80);
selected_brand_button->setMaximumHeight(80);
selected_brand_button->setMaximumWidth(80);
selected_brand_button->setStyleSheet(style_toolbutton);
ui->verticalLayout_selections->addWidget(selected_brand_button);
connect(selected_brand_button, SIGNAL(clicked()), signalMapperSelections, SLOT(map()));
signalMapperSelections->setMapping(selected_brand_button, get_selected_brand());
connect(signalMapperSelections, SIGNAL(mapped(QString)), this, SLOT(show_models(QString)));
When I click "selected_type_button" I only want to run "show_brands". But it's running both functions, "show_brands" and "show_models"...
I tried Qt::UniqueConnection, but it doesn't fix this problem.
I think this is happening because both buttons are using the same signal... But I don't know how to fix it.
How can I fix this?
When I click "selected_type_button" I only want to run "show_brands".
There is no reason to use QSignalMapper in your situation at all. You just have to connect clicked signal from selected_type_button to the show_brands slot, and clicked signal from selected_brand_button to the show_models slot.
QString is the selected type or selected brand....
This QString argument has nothing to do with the clicked signal's source (So, it does not need any mapping using QSignalMapper, read about QSignalMapper in the docs here). The mapping you are currently using is set up at the connection time (not at emit time) , this means that get_selected_type()/get_selected_brand() will return the selected items at the time of calling setMapping (this is obviously not what you meant).
To get the item at the time of clicking the button, you can call your get_selected_type()/get_selected_brand() functions in your slots directly, your code will be something like this:
QPushButton *selected_type_button = new QPushButton();
selected_type_button->setObjectName("selected_type_button");
selected_type_button->setText(get_selected_type().replace(" ", "\n"));
selected_type_button->setMinimumHeight(80);
selected_type_button->setMinimumWidth(80);
selected_type_button->setMaximumHeight(80);
selected_type_button->setMaximumWidth(80);
selected_type_button->setStyleSheet(style_toolbutton);
ui->verticalLayout_selections->addWidget(selected_type_button);
//Qt 5 new connect syntax (replace ClassName with the current class's name)
connect(selected_type_button, &QPushButton::clicked, this, &ClassName::show_brands);
QPushButton *selected_brand_button = new QPushButton();
selected_brand_button->setObjectName("selected_brand_button");
selected_brand_button->setText(get_selected_brand().replace(" ", "\n"));
selected_brand_button->setMinimumHeight(80);
selected_brand_button->setMinimumWidth(80);
selected_brand_button->setMaximumHeight(80);
selected_brand_button->setMaximumWidth(80);
selected_brand_button->setStyleSheet(style_toolbutton);
ui->verticalLayout_selections->addWidget(selected_brand_button);
//replace ClassName with the current class's name)
connect(selected_brand_button, &QPushButton::clicked, this, &ClassName::show_models);
and your show_brands slot should look something like:
//no need for the QString argument
void ClassName::show_brands(){
QString selectedType= get_selected_type();
//show_brands here
}
the same thing for show_models slot:
void ClassName::show_models(){
QString selectedBrand= get_selected_brand();
//show_models here
}

Qt RightClick on QListWidget Opens Contextmenu and Delete Item

I want to know how can I open a popup menu when I right click on the table items. In the popup menu some actions like add and delete should be given, which will create a new row or delete the selected row.
I am a new in the Qt world, so if anybody can give me the full details (with code if possible) then I will be really grateful towards him/her.
Thank you.
My goal: Only in the area of QListWidget and only if you click on an item, the menu with Delete will be opened.
Edit : Ok I solved the problem with the QListWidget and the menu. Now the following must be accomplished:
If you click on an item with the right mouse button, and then click Delete, then the item will be deleted.
My code:
void ProvideContextMenu(const QPoint &); // MainWindow.h
// In MainWindow.cpp
ui->listFiles->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->listFiles, SIGNAL(customContextMenuRequested(const QPoint &)),
this, SLOT(ProvideContextMenu(const QPoint &)));
void MainWindow::ProvideContextMenu(const QPoint &pos)
{
QPoint item = ui->listFiles->mapToGlobal(pos);
QMenu submenu;
submenu.addAction("ADD");
submenu.addAction("Delete");
QAction* rightClickItem = submenu.exec(item);
if (rightClickItem && rightClickItem->text().contains("Delete") )
{
ui->listFiles->takeItem(ui->listFiles->indexAt(pos).row());
}
}
Edit2 : Ok I solved the whole problem :D. I uploaded my code, if somebody needs something like that it can help him/her.
Firstly you need to create slot for opening context menu:
void showContextMenu(const QPoint&);
At constructor of your class, which used QListWidget, set context menu policy to custom and connect QListWidget::customContextMenuRequested(QPoint) signal and showContextMenu() slot like this:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
setupUi(this);
listWidget->setContextMenuPolicy(Qt::CustomContextMenu);
connect(listWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint)));
}
Then need to realize context menu opening:
void MainWindow::showContextMenu(const QPoint &pos)
{
// Handle global position
QPoint globalPos = listWidget->mapToGlobal(pos);
// Create menu and insert some actions
QMenu myMenu;
myMenu.addAction("Insert", this, SLOT(addItem()));
myMenu.addAction("Erase", this, SLOT(eraseItem()));
// Show context menu at handling position
myMenu.exec(globalPos);
}
After this we need to realize slots for adding and removing QListWidget elements:
void MainWindow::eraseItem()
{
// If multiple selection is on, we need to erase all selected items
for (int i = 0; i < listWidget->selectedItems().size(); ++i) {
// Get curent item on selected row
QListWidgetItem *item = listWidget->takeItem(listWidget->currentRow());
// And remove it
delete item;
}
}
As you can see we iterate all selected items (for set multiple selection mode use setSelectionMode() method) and delete it by ourself, because docs says that
Items removed from a list widget will not be managed by Qt, and will
need to be deleted manually.
Adding some items is easier, my solution with static variable for different item caption looks like:
void MainWindow::addItem()
{
static int i = 0;
listWidget->addItem(QString::number(++i));
}
To simplify your code use Qt5 sytax for signals and slots. It eliminates the need to create intermediate slots.
I hope it helps to you.
It's much simpler than the accepted answer. You don't need to deal with creating a context menu or cursor positions or any of that. Instead of Qt::CustomContextMenu, use Qt::ActionsContextMenu and just add your actions directly to the widget:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
ui->setupUi(this);
// you can create the actions here, or in designer
auto actInsert = new QAction("Insert", this);
auto actDelete = new QAction("Delete", this);
// you can set up slot connections here or in designer
connect(actInsert, SIGNAL(triggered()), this, SLOT(addItem()));
connect(actDelete, SIGNAL(triggered()), this, SLOT(eraseItem()));
// and this will take care of everything else:
listWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
listWidget->addActions({ actInsert, actDelete });
}
void MainWindow::addItem () {
...; // add an item
}
void MainWindow::eraseItem () {
...; // erase an item
}
Everything above except addActions (I think) can also be done in Designer.
Alternatively, if you don't want to add actual slot functions for whatever reason, you can do everything in a lambda on connect, too:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
ui->setupUi(this);
// you can create the actions here, or in designer
auto actInsert = new QAction("Insert", this);
auto actDelete = new QAction("Delete", this);
connect(actInsert, &QAction::triggered, [=]() {
...; // add an item
});
connect(actDelete, &QAction::triggered, [=]() {
...; // erase an item
});
// and this will take care of everything else:
listWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
listWidget->addActions({ actInsert, actDelete });
}
The signal/slot option is more organized and flexible, but the lambda option is good for short highly specialized bits of code (or binding to functions that aren't slots).
This works for context menus on any widget. Also, the same QAction can be used on multiple widgets.

Slot is not being used

I'm learning the signals/slots in Qt and I have found a problem. I need to create my own slot that is called when items on QGraphicsScene (in QGraphicsView) are moved or selected.
I'm starting with a simple app that has one widget and on it is graphicsView and label. I've created a slot in my window and connected it to QGraphicsScene's signal, but it is not being used. Where is my mistake?
Here is the code:
//MainWindow.h
//as generated by QtCreator, just added one slot to it
...omitted for brevity...
public slots:
void selectedItemChanged(QGraphicsItem * newItem, QgraphicsItem * oldItem);
..omitted for brevity...
//------------------------------------------------------------------
//MainWindow.cpp
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
QGraphicsScene * scene = new QGraphicsScene();
scene->setBackgroundBrush (QBrush(Qt::gray));
ui->graphicsView->setScene (scene);
for(int x = 10; x < 250; x+=20)
{
QGraphicsEllipseItem * item = scene->addEllipse (x,x,5,5,QPen(Qt::darkGreen),QBrush(Qt::darkGreen));
item->setFlag (QGraphicsItem::ItemIsFocusable,true);
}
QObject::connect (scene,SIGNAL(focusItemChanged),this,SLOT(selectedItemChanged));
}
void MainWindow::selectedItemChanged (QGraphicsItem *newItem, QGraphicsItem *oldItem)
{
qDebug()<<"called";
if(newItem == 0)
{
ui->label->setText ("Není vybrán bod");
}
else
{
ui->label->setText (QString::number (newItem->scenePos ().x ()) + "," + QString::number (newItem->scenePos ().y ()));
}
}
Now, when I run the probram it rins ok, but I cannot set Focus on the circles(ellipses) drawn on the scene and the slot is not used. I tried setting IsSelectable flag, but it does not help. Is there any other preferred way to get this done or solution to my problem?
You're not linking against the signal's right signature, according to the documentation:
void QGraphicsScene::focusItemChanged( QGraphicsItem * newFocus, QGraphicsItem * oldFocus,
Qt::FocusReason reason)
and also notice that you can check the connection's success/failure status via the bool return type of the QObject::connect method
So, in the end i found the answer to my own question. It was a mistake on my side.
in the connect() i used the slots without parenthesis/parameters. It should have looked like:
QObject::connect (scene,
SIGNAL(focusItemChanged(QGraphicsItem*,QGraphicsItem*,Qt::FocusReason)),
this,
SLOT(selectedItemChanged(QGraphicsItem*,QGraphicsItem*)));

How to get the text from a QLineEdit widget and use it in a State Machine?

I am trying to create a program that waits for the user to input something into a line edit widget, and when they hit enter, I want to compare the value to some predefined one (for example "1"). The problem I seem to be having is that I cannot find a way to make this work with the QStateMachine. At the moment, it will wait for the user to press enter and it just switches over to the next state, but I want it to only go to the next state if the input is "1". Here is the code I am using and thank you for any help that you can offer.
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->lineEdit, SIGNAL(editingFinished()), this, SLOT(someSlot()));
setupStateMachine();
}
...
void MainWindow::setupStateMachine()
{
QStateMachine *machine = new QStateMachine(this);
QState *s1 = new QState();
QState *s2 = new QState();
QState *s3 = new QState();
s1->assignProperty(ui->label, "text", readFile("intro.txt"));
s2->assignProperty(ui->label, "text", "In state s2");
s3->assignProperty(ui->label, "text", "In state s3");
s1->addTransition(this, SIGNAL(editing()), s2);
s2->addTransition(this->ui->pushButton, SIGNAL(clicked()), s3);
s3->addTransition(this->ui->pushButton, SIGNAL(clicked()), s1);
machine->addState(s1);
machine->addState(s2);
machine->addState(s3);
machine->setInitialState(s1);
machine->start();
qDebug() << "State Machine Created";
}
...
void MainWindow::someSlot()
{
if(ui->lineEdit->text() == "1")
{
emit editing();
}
}
In the header file:
{
...
signals:
void editing();
...
private slots:
void someSlot();
...
};
PS: I realize that the signal does not do what I want, but I can't figure out which signal to use.
Perhaps you can connect editingFinished to your own slot. In that slot, check if the input is "1". if so, emit a new signal you pass into addTransition instead of editingFinished
To add a signal to a class, change the class like this (make sure there is a Q_OBJECT declared at the very top of the class):
signals:
void mySignalName();
Signals are guaranteed protected. You don't write the body of the function. That's what MOC does. So, when you want to call the signal in your class, just call:
emit mySignalName();
emit is just for code documentation. It's #defined to nothing. MOC will generate the body of mySignalName and boil down to calls to the slots you connect it to using QObject::connect.
To add a new slot to your class, add this:
private slots:
void mySlotName();
Note that you will have to write the body of a slot.
void MainWindow::mySlotName()
{
if(myLineEdit->text() == "1")
emit mySignalName();
}