Hello I have created an application using qt and I managed to save some of its settings using QSettings.
void DoneIt::writeSettings()
{
QSettings settings("mycompany", "RightDoneIt");
settings.beginGroup("DoneIt");
settings.setValue("size", size());
settings.setValue("pos", pos());
settings.endGroup();
}
void DoneIt::readSettings()
{
QSettings settings("mycompany", "RightDoneIt");
settings.beginGroup("DoneIT");
resize(settings.value("size", QSize(400, 400)).toSize());
move(settings.value("pos", QPoint(200, 200)).toPoint());
settings.endGroup();
}
That works fine with the window position and size.
I have add some widgets in my application using the designer of qt and I would like to save their state too.
One of my widgets is a radio button and I call it radioButtonbnw
How can I save its state (checked or unchecked) ?
What are the best practises ?
Put them to QButtonGroup.
Use QButtonGroup::setId to set Id for each radio button in this group.
Save the Id of the checked button get by QButtonGroup::checkedId.
Get the pointer of this button using QButtonGroup::button(id) when restore, and call QAbstractButton::setChecked.
BTW: if you want to saves the current state of mainwindow's toolbars and dockwidgets, use QMainWindow::saveState.
Here an example widget with three QRadioButton
settingspane.h
#ifndef SETTINGSPANE_H
#define SETTINGSPANE_H
#include <QWidget>
#include <QSettings>
class SettingsPane
: public QWidget
{
Q_OBJECT
QSettings *settings;
public:
explicit SettingsPane(QWidget *parent = nullptr);
public slots:
void handle_rb_buttonReleased(int id);
};
#endif // SETTINGSPANE_H
settingspane.cpp
#include "settingspane.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QRadioButton>
#include <QButtonGroup>
SettingsPane::SettingsPane(QWidget *parent)
: QWidget(parent)
{
settings = new QSettings();
auto mlayout = new QVBoxLayout();
setLayout(mlayout);
// create some buttons
auto rb_frst = new QRadioButton("first");
auto rb_scnd = new QRadioButton("second");
auto rb_thrd = new QRadioButton("third");
// container to organize groups of buttons (no visual)
auto buttonGroup = new QButtonGroup();
buttonGroup->addButton(rb_frst,0);
buttonGroup->addButton(rb_scnd,1);
buttonGroup->addButton(rb_thrd,2);
// layout buttons for visual representation
auto rb_layout = new QHBoxLayout();
rb_layout->addWidget(rb_frst);
rb_layout->addWidget(rb_scnd);
rb_layout->addWidget(rb_thrd);
mlayout->addLayout(rb_layout);
// use Functor-Based Connection due to overloaded buttonReleased
connect( buttonGroup,
SIGNAL(buttonReleased(int)),
this,
SLOT(handle_rb_buttonReleased(int)));
// restore button from settings
int id = settings->value("buttonGroup").toInt();
buttonGroup->button(id)->setChecked(true);
}
void
SettingsPane::handle_rb_buttonReleased(int id)
{
// save new status to the settings
settings->setValue("buttonGroup", id);
}
Using this in a MainWindow
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class MainWindow
: public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "settingspane.h"
#include <QTabWidget>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
auto cwidget = new QTabWidget();
setCentralWidget(cwidget);
auto settingsPane = new SettingsPane();
cwidget->addTab(settingsPane,"Settings");
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
results in:
Related
EDIT:
NOTE this only occurs when the button is in a SUBMENU. (Menu in a menu.) This code works fine only on the parent menu!
Running Qt 5.0.2, on Windows 7. I have a QMenu with a QWidgetAction in it. Inside the QWidgetAction is a QPushButton. I would like to change the background color of the button when the mouse hovers over it.
Here is my code:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QMenu>
#include <QWidgetAction>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
QMenu menu;
QMenu *subMenu = new QMenu("SubMenu text");
QWidgetAction *widgetAction = new QWidgetAction(subMenu);
QPushButton *btn = new QPushButton("test");
btn->setStyleSheet("QPushButton:hover{background-color: #ff0000;}");
widgetAction->setDefaultWidget(btn);
subMenu->addAction(widgetAction);
menu.addMenu(subMenu);
menu.exec();
}
.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
};
#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();
}
However when the cursor hovers over the QPushButton the background color doesn't change. Doesn't matter if I run it in fusion style or not.
What is going on here? Thanks for your time.
This sound like mouseTracking is not enabled on the widget (and/or probably on the parent widget(s)). You can enable it by calling
QWidget::setMouseTracking(bool enable);
Background may not be customized, if you don't change a border style of a button.
How to solve: use some non-default style, for example:
const auto fusion = QStyleFactory::create( "Fusion" );
QApplication::setStyle( fusion );
QPushButton is not designed for perfect handling hover events. For example, hover event will not change a font via stylesheet.
How to solve: use QToolButton instead.
P.S. Don't know, why it's not worked for you. Everything is OK for me...
UPDATE
Just copy-paste it and run:
#include <QApplication>
#include <QWidgetAction>
#include <QMenu>
#include <QPushButton>
#include <QToolButton>
#include <QStyleFactory>
void showMenu()
{
const auto parent = qApp->activeWindow();
auto menu = new QMenu( parent );
auto root = new QMenu( "Root", menu );
menu->addMenu( root );
auto wa = new QWidgetAction( parent );
auto tb = new QToolButton;
tb->setText( "ToolBtn" );
wa->setDefaultWidget( tb );
root->addAction( wa );
menu->exec( QCursor::pos() );
menu->deleteLater();
}
int main(int argc, char *argv[])
{
QApplication a( argc, argv );
const auto fusion = QStyleFactory::create( "Fusion" );
const auto qss =
"QToolButton:!hover{background-color: #00ff00;}"
"QToolButton:hover{background-color: #ff0000;}"
;
QApplication::setStyle( fusion );
qApp->setStyleSheet( qss );
QWidget w;
w.resize( 800, 600 );
auto btn = new QPushButton{ "Test", &w };
QObject::connect( btn, &QPushButton::clicked, &showMenu );
w.show();
return a.exec();
}
In a Qt/C++ piece of code, I have a QTabWidget class with different tabs.
I would like to add a last "+" tab, so when the user is clicking on it, I create a new tab.
However I would like to have all my tabs closable ('x' at the right of the tab), except the last one where I don't want the 'x' to be displayed. How can I have this granularity in the closable flag ?
Surprised to see that this is not yet answered. Had some time and I have implemented a working example. Note that instead of using one of the tabs as your "+" button, I have used QToolButton thereby making it simpler to make tabs closable with QTabWidget::setTabsClosable(bool)
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTabWidget>
#include <QToolButton>
#include <QLabel>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
QTabWidget* _pTabWidget;
private slots:
void slotAddTab();
void slotCloseTab(int);
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
_pTabWidget = new QTabWidget(this);
this->setCentralWidget(_pTabWidget);
// Create button what must be placed in tabs row
QToolButton* tb = new QToolButton(this);
tb->setText("+");
// Add empty, not enabled tab to tabWidget
_pTabWidget->addTab(new QLabel("Add tabs by pressing \"+\""), QString());
_pTabWidget->setTabEnabled(0, false);
// Add tab button to current tab. Button will be enabled, but tab -- not
_pTabWidget->tabBar()->setTabButton(0, QTabBar::RightSide, tb);
// Setting tabs closable and movable
_pTabWidget->setTabsClosable(true);
_pTabWidget->setMovable(true);
connect(tb,SIGNAL(clicked()),this,SLOT(slotAddTab()));
connect(_pTabWidget,SIGNAL(tabCloseRequested(int)),this,SLOT(slotCloseTab(int)));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::slotAddTab()
{
QWidget* newTab = new QWidget(_pTabWidget);
_pTabWidget->addTab(newTab, tr("Tab %1").arg(QString::number(_pTabWidget->count())));
_pTabWidget->setCurrentWidget(newTab);
}
void MainWindow::slotCloseTab(int index)
{
delete _pTabWidget->widget(index);
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
What it should do: When the QComboBox is on the first item (index 0) it should hide the QStackedWidget. Which causes the QComboBox to extend as much as possible. As soon as you change the item in the QComboBox to anything, the QComboxBox should shrink and the QStackedWidget should display the correct page.
What I have and what it does instead: I test what the current index item is of the QComboBox and depending on that I change the size policies and visibility of widgets in order to obtain what I want. But it doesn't work. I tried to do workarounds but I cant seem to figure this out.
I also used qDebug() to see what currentIndexItem returns, and it seems to be stuck at 0, no matter to what index I change the QComboBox to. Do I have to update the currentItemIndex?
Note: I have a signal connected in the designer from QComboBox to QStackedWidget: currentIndexChanged(int) -> setCurrentIndex(int)
Here is my code.
My code:
interfacewindow.h
#ifndef INTERFACEWINDOW_H
#define INTERFACEWINDOW_H
#include <QMainWindow>
#include <QPainter>
#include <QComboBox>
namespace Ui
{
class InterfaceWindow;
}
class InterfaceWindow : public QMainWindow
{
Q_OBJECT
public:
explicit InterfaceWindow(QWidget *parent = 0);
~InterfaceWindow();
private:
Ui::InterfaceWindow *ui;
private slots:
void on_actionClose_triggered();
};
#endif // INTERFACEWINDOW_H
interfacewindow.cpp
#include "interfacewindow.h"
#include "ui_interfacewindow.h"
#include <QDebug>
InterfaceWindow::InterfaceWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::InterfaceWindow)
{
ui->setupUi(this);
if(ui->comboBox->currentIndex() == 0)
{
ui->comboBox->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
ui->stackedWidget->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
ui->stackedWidget->setVisible(false);
}
else
{
ui->comboBox->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
ui->stackedWidget->setVisible(true);
}
}
InterfaceWindow::~InterfaceWindow()
{
delete ui;
}
void InterfaceWindow::on_actionClose_triggered()
{
this->close();
}
main.cpp
#include <QApplication>
#include "interfacewindow.h"
int main(int argc, char **argv)
{
QApplication a(argc, argv);
InterfaceWindow w;
w.show();
return a.exec();
}
I have a main window which opens a new window and connects a button from the new window to a "close" function. The problem arises when that new window has more than one button; it will always connect the last created button instead of the explicited one. Here is a sample working code:
"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 "screen_char_info.h"
#include <QMainWindow>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
QPushButton *button_show_char_info;
Screen_Char_Info *screen_char_info;
QWidget *mainwidget;
QVBoxLayout *layout_main;
MainWindow(QWidget *parent = 0) : QMainWindow(parent) {
button_show_char_info = new QPushButton("Character info", this);
layout_main = new QVBoxLayout();
mainwidget = new QWidget(this);
screen_char_info = NULL;
QObject::connect (button_show_char_info, &QPushButton::clicked, [this]{
if (screen_char_info == NULL) {
screen_char_info = new Screen_Char_Info();
screen_char_info->show();
QObject::connect (screen_char_info->button_return, &QPushButton::clicked, [=] {
screen_char_info->close();
screen_char_info = NULL;
});
}
});
layout_main->addWidget(button_show_char_info);
mainwidget->setLayout(layout_main);
setCentralWidget(mainwidget);
}
~MainWindow()
{
}
};
#endif // MAINWINDOW_H
"screen_char_info.h"
#ifndef SCREEN_CHAR_INFO_H
#define SCREEN_CHAR_INFO_H
#include <QString>
#include <QMenu>
#include <QMenuBar>
#include <QLabel>
#include <QTextEdit>
#include <QPushButton>
#include <QWidget>
#include <QLineEdit>
#include <QGridLayout>
class Screen_Char_Info : public QWidget {
Q_OBJECT
public:
QPushButton *buttons_modify_attributes[15];
QPushButton *button_return;
QGridLayout *layout;
Screen_Char_Info () {
this->setAttribute(Qt::WA_DeleteOnClose);
this->setWindowTitle("Character Info");
layout = new QGridLayout(this);
for (int i = 0; i <= 15; i++) {
buttons_modify_attributes[i] = new QPushButton((i%2 ? "-" : "+"), this);
connect(buttons_modify_attributes[i], &QPushButton::clicked, [this] {
});
layout->addWidget(buttons_modify_attributes[i], (i / 2), (i % 2), 1, 1);
}
layout->addWidget(button_return = new QPushButton("Return", this), 8, 0, 1, 1);
this->setLayout(layout);
}
};
#endif // SCREEN_CHAR_INFO_H
However, if i put the line layout->addWidget(button_return... before the for loop, the button that closes the window is the last "-" button, and not the return one.
The way you do the connect does not appear to be conventional. Try using traditional Qt way:
connect(pButtonToPress, SIGNAL(clicked()), pObjectToHandle, SLOT(onClicked));
Provided QPushButton* pButtonPress actually pointing to QPushButton and pObjectToHandle to some object (can be 'this' pointer):
class ObjHandler
{
public slot:
void onClicked();
};
... should satisfy. SIGNAL and SLOT are macro that work with some help of Qt meta object compiler. That is why having slot: statement is highly critical.
Found the bug, I was declaring a button matrix with 15 elements, but iterating over a 16 element loop. The 16th element was the return button, and was overwritten in the loop.
Alright so is there any way to make this program randomly change the variables x and y every time the button is clicked i am new to programming...
#include <QtGui/QApplication>
#include "mainwindow.h"
#include <QtGUI>
#include <QWidget>
#include <cstdlib>
#include <ctime>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget *window = new QWidget;
srand(time(0));
int x = 1+(rand()%900);
int y = 1+(rand()%400);
QPushButton *MainInter = new QPushButton("Push me!",window);
QPropertyAnimation *animation = new QPropertyAnimation(MainInter, "pos");
animation->setDuration(0);
animation->setEndValue(QPoint(x,y));
Object::connect(MainInter,SIGNAL(released()),animation,SLOT(start()));
window->resize(900,500);
window->show();
return a.exec();
}
What you can do is, instead of connecting the released() signal of your button directly to your animations start() SLOT, you would create your own custom SLOT. Then you connect the button to it, handle the action, and call the animation.
First read up on how to create a custom QWidget, instead of creating top level object in your main(). Simple example here
A custom widget might look like this:
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
class QPushButton;
class QPropertyAnimation;
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget *parent = 0);
private:
QPushButton *button;
QPropertyAnimation *animation;
public slots:
void randomizeAnim();
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include <QPushButton>
#include <QPropertyAnimation>
#include <ctime>
MyWidget::MyWidget(QWidget *parent) :
QWidget(parent)
{
button = new QPushButton("Push me!", this);
animation = new QPropertyAnimation(button, "pos");
animation->setDuration(0);
QObject::connect(button, SIGNAL(released()), this, SLOT(randomizeAnim()));
}
void MyWidget::randomizeAnim()
{
srand(time(0));
int x = 1+(rand()%900);
int y = 1+(rand()%400);
animation->setEndValue(QPoint(x,y));
animation->start();
}
And now your main.cpp can be reduced to the boilerplate code:
#include <QApplication>
#include "widget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget *window = new MyWidget;
window->resize(900,500);
window->show();
return a.exec();
}
Every time you click, your custom slot will handle the action and do the animation.