In the first picture I designed a prototype. The MainWindow includes widget and three frames. The center frame has another frame, and when I run in the application in full screen there is a size problem in the center frame, as you can see in the second picture. I want to center the frame in its frame. How can I do that?
You can do it easily from Qt Designer. Just add another Horizontal Layout into the middle Frame. Then add your Widget into the layout, go to the Object Manager, call context menu on your widget, click Layout Alignment and choose Center horizontally.
Here is the .ui file which I have just created to check your problem:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>965</width>
<height>502</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QFrame" name="frame_2">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_3">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<widget class="QWidget" name="horizontalLayoutWidget_2">
<property name="geometry">
<rect>
<x>9</x>
<y>9</y>
<width>291</width>
<height>411</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item alignment="Qt::AlignHCenter|Qt::AlignVCenter">
<widget class="QListWidget" name="listWidget"/>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>965</width>
<height>23</height>
</rect>
</property>
</widget>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar"/>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>
Edition 1: Basically with above example I managed to reproduce your bug. I have added horizontal layout inside middle frame but while changing the size middle widget has aligned to the left side.
The answer on your question is here: Make QHorizontalLayout expand inside QFrame
You have to add Horizontal Layout into your middle Frame. Then you have to call context menu of the Middle Frame, click Layout -> Layout Horizontally. Add your widget in the layout. Most probably you widget will expand its width to the width of the Main Window. Change SizePolicy to fixed. At this point your problem should be solved.
you can create programatically like this:
overwrite this functions: QSize sizeHint() and QSize minimumSizeHint()
here an example:
.h
#ifndef LATERALBOARD_H
#define LATERALBOARD_H
#include <QBasicTimer>
#include <QFrame>
#include <QPointer>
QT_BEGIN_NAMESPACE
class QLabel;
QT_END_NAMESPACE
class LateralBoard : public QFrame
{
Q_OBJECT
public:
LateralBoard(QWidget *parent = nullptr);
QSize sizeHint() const override;
QSize minimumSizeHint() const override;
private:
enum { BoardWidth = 10, BoardHeight = 12 };
};
#endif
.cpp
#include <QKeyEvent>
#include <QLabel>
#include <QPainter>
LateralBoard::LateralBoard(QWidget *parent)
: QFrame(parent)
{
setFrameStyle(QFrame::Panel | QFrame::Sunken);
setFocusPolicy(Qt::StrongFocus);
}
QSize LateralBoard::sizeHint() const
{
return QSize(100, 100);
}
QSize LateralBoard::minimumSizeHint() const
{
return QSize(BoardWidth * 5 + frameWidth() * 2,
BoardHeight * 5 + frameWidth() * 2);
}
and in your main window you should use a layout to set the position
QGridLayout *layout = new QGridLayout;
LateralBoard *lateralBoard = new LateralBoard;
layout->addWidget(lateralBoard, 2, 6);
setLayout(layout);
Related
I have a MainWindow class and within it a QStackWidget.
Inside it I have another 3 widgets, each one is my own custom class derived from QWidget.
Inside one of the widgets I have a button.
When I am using QT Creator and press Go to slot.. on the button, it creates an on_button_clicked event in MainWindow class.
How do I change it to have the event inside my custom class?
UPDATE:
I can see that the buttons are located in MainWindow. This is auto generated, so I am not sure how to move it.
Code:
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_2_clicked()
{
QMessageBox::information(this, "Button 2 clicked!", "Click");
}
mainwindow.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>668</width>
<height>630</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<widget class="QStackedWidget" name="stackedWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>531</width>
<height>391</height>
</rect>
</property>
<property name="currentIndex">
<number>1</number>
</property>
<widget class="Stack1" name="page">
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>140</x>
<y>110</y>
<width>321</width>
<height>121</height>
</rect>
</property>
<property name="text">
<string>Button on Stack1</string>
</property>
</widget>
</widget>
<widget class="Stack2" name="page_2">
<widget class="QPushButton" name="pushButton_2">
<property name="geometry">
<rect>
<x>110</x>
<y>140</y>
<width>371</width>
<height>161</height>
</rect>
</property>
<property name="text">
<string>Button on stack2</string>
</property>
</widget>
</widget>
</widget>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>668</width>
<height>25</height>
</rect>
</property>
</widget>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar"/>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>Stack1</class>
<extends>QWidget</extends>
<header>stack1.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>Stack2</class>
<extends>QWidget</extends>
<header>stack2.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
I want the button callback to be inside my custom class stack2.cpp
#include "stack2.h"
Stack2::Stack2(QWidget *parent) : QWidget(parent)
{
}
Stack2::~Stack2()
{
}
You made promotion correctly but you should not fill contents of promoted widgets in main window form (i.e. put buttons in them). Instead, create stack page classes as Designer Form Classes (just as MainWindow but based on QWidget) and put contents in them using separate form editor. Alternatively, you can add layouts and buttons to stack pages manually in their constructors.
I am new to qt So I don't have much knowledge of sizepolicy and streches of widgets.
I have a vertical box layout in which I have first added a Qlabel and then a QTreeWidget and then again a Qlabel. Now the problem is QTreeWidget is taking full space in vertical direction and then after leaving a very big space after QTreeWidget, although only rows exist currently in it, QLabel is added. I want that second Qlabel is added immediately after two rows visible and now when more rows are added then It shift downwards. Can someone suggest me how to do this?
I think this is what you meant:
UI has in a layout: Label, QTreeWidget, Label, Spacer
(Spacer is important becaus else Qt might just expand the labels to fill the window.)
Important: In Designer TreeWidget hight to preffered, vertical scrollbar off.
UI Example:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>517</width>
<height>568</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item>
<widget class="my_tree" name="treeView">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAsNeeded</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>517</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar"/>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>my_tree</class>
<extends>QTreeView</extends>
<header>my_tree.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
A Overloaded QTreeView (in your case QTreeWidget) is used to get the wanted sizehints:
EDIT -- This is a uggly header only definition i called my_tree.h --
#ifndef MY_TREE_H
#define MY_TREE_H
#include <QHeaderView>
#include <QTreeView>
class my_tree: public QTreeView
{
Q_OBJECT
public:
my_tree(QWidget* parent):QTreeView(parent)
{
// Important: if something is shown/hidden we need a new size
connect(this,SIGNAL(expanded( const QModelIndex & )),SLOT(onExpandCollapsed()));
connect(this,SIGNAL(collapsed( const QModelIndex & )),SLOT(onExpandCollapsed()));
};
// QWidget interface
public:
QSize sizeHint() const {return my_size(); };
QSize minimumSizeHint() const { return my_size(); };
private:
QSize my_size() const
{ //QSize tst(sizeHintForColumn(0) + 2 * frameWidth(), sizeHintForRow(0) + 2 * frameWidth());
int neededHight= 2 * frameWidth()+ this->header()->height();
QModelIndex root = this->rootIndex();
QAbstractItemModel* m = this->model();
//if(this->rootIsDecorated())
{
neededHight += recursiveHeightHint(root,m);
}
QSize temp = QTreeView::sizeHint();
temp.setHeight(neededHight);
return QSize(1,neededHight);
}
// we need the size of all visible items -> isExpanded
// the root item is usually shown as a non-Valid index -> !i.isValid()
int recursiveHeightHint(QModelIndex i,QAbstractItemModel* m) const
{
int temp=sizeHintForIndex(i).height();
if(this->isExpanded(i) || !i.isValid())
{
if(m->hasChildren(i))
{
int numRows = m->rowCount(i);
for(int count =0;count<numRows;count++)
temp+=recursiveHeightHint(m->index(count,0,i),m);
}
}
return temp;
}
private slots:
void onExpandCollapsed(){updateGeometry();}
};
#endif // MY_TREE_H
PS: in Designer first place the base Widget and then define it as placeholder for the self designed one.
I used this entry to get to this solution:
QListWidget adjust size to content
I have added two pushButtons using qtDesigner, those buttons are chilldren of centralWidget, now I would like to add one more pushButton, but programmatically in mainwindow.cpp.
When I use setCentralWidget method it removes or hides prevous 2 pushButtons which were added by qtDesigner. My question is how to add this additional button programmatically so those 2 pushButtons remains?
I am beginner in Qt.
The central widget default layout is called gridLayout and is a QGridLayout. You can add the new button to it like this:
ui->gridLayout->addWidget(new QPushButton("Button Text"), rowNumber, colNumber);
Here is an example:
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class QPushButton;
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
QPushButton *newButton;
};
#endif // MAINWINDOW_H
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPushButton>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
newButton(new QPushButton("Button 3"))
{
ui->setupUi(this);
const int rowNumber = 1;
const int colNumber = 0;
ui->gridLayout->addWidget(newButton, rowNumber, colNumber);
}
MainWindow::~MainWindow()
{
delete ui;
}
mainwindow.ui:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QPushButton" name="pushButton1">
<property name="text">
<string>Button 1</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="pushButton2">
<property name="text">
<string>Button 2</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar"/>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>
Good luck!
You can add QPushbutton to central widget by passing its object name.
QPushButton *PB=new QPushButton(ui->centralwidgetobjectname);
PB.show();
Otherwise create layout inside Central widget then using addwidget function to add Qpushbutton.
QGridLayout *GL=new QGridLayout(this);
QPushButton *PB=new QPushButton();
GL->addWidget(PB);
Set Geometry For Grid Layout.
I am trying to create a background application using Qt.
There is a difference of ui between running in the foreground and running as a deamon.
The style has been changed since Ubuntu 11.10.
when running the application in the Foreground
when running as a daemon
main.cpp
#include <QApplication>
#include "form.h"
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
Form *pForm = new Form();
pForm->show();
return app.exec();
}
form.h
#include <QWidget>
namespace Ui {
class form;
}
class Form : public QWidget
{
Q_OBJECT
public:
explicit Form(QWidget *parent = 0);
private:
Ui::form *ui;
};
form.cpp
#include "form.h"
#include "ui_form.h"
Form::Form(QWidget *parent) : QWidget(parent)
, ui(new Ui::form)
{
ui->setupUi(this);
ui->label->setText(QT_VERSION_STR);
}
form.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>form</class>
<widget class="QWidget" name="form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>270</x>
<y>240</y>
<width>98</width>
<height>27</height>
</rect>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
<widget class="QTabWidget" name="tabWidget">
<property name="geometry">
<rect>
<x>30</x>
<y>30</y>
<width>341</width>
<height>191</height>
</rect>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Tab 1</string>
</attribute>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Tab 2</string>
</attribute>
</widget>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>50</x>
<y>240</y>
<width>141</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string/>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>
It's just simple Ui to test.
I think the application in the foreground applies 'Desktop Settings' as a GUI style, but I don't know which style is used on a daemon application (image on the right above) .
Why the style is different?
In order to have unified style on any platform or envirovment you need to set application style explicitly:
QApplication app(argc, argv);
app.setStyle(new QPlastiqueStyle()); //or similar.
When I promote a QWidget to a custom widget in QtDesigner, everything compiles fine, but when I run the program the widget seems to be blank. I have made a very simple demo of this:
Form.h
#ifndef FORM_H
#define FORM_H
#include <QWidget>
#include "ui_form.h"
class Form : public QWidget, private Ui::Form
{
Q_OBJECT
public:
Form(QWidget *parent = 0);
};
#endif
Form.cpp
#include "form.h"
Form::Form(QWidget* parent)
: QWidget(parent)
{
setupUi(this);
}
TestWidget.h
#ifndef TestWidget_H
#define TestWidget_H
#include "ui_TestWidget.h"
#include <QMainWindow>
class TestWidget : public QWidget, private Ui::TestWidget
{
Q_OBJECT
public:
TestWidget(QWidget *parent = 0);
};
#endif
TestWidget.cpp
#include "TestWidget.h"
TestWidget::TestWidget(QWidget *parent)
: QWidget(parent)
{
}
main.cpp
#include <QApplication>
#include "form.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Form form;
form.show();
return app.exec();
}
Form.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>532</width>
<height>341</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="TestWidget" name="widget" native="true">
<property name="geometry">
<rect>
<x>130</x>
<y>90</y>
<width>161</width>
<height>121</height>
</rect>
</property>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>TestWidget</class>
<extends>QWidget</extends>
<header>TestWidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
TestWidget.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TestWidget</class>
<widget class="QWidget" name="TestWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>306</width>
<height>60</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Current path:</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
When I run this, I just see a blank widget, when I would expect to see the label with "Current path:" displayed.
I just needed to add
setupUi(this);
to the TestWidget constructor.
If I were able to comment I would put this there... need more rep still though before that is an option.
Looking at the geometry of the TestWidget I see that it is 306 pixels wide:
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
**<width>306</width>**
<height>60</height>
</rect>
</property>
In Form.ui, you're giving it only 161 pixels:
<widget class="TestWidget" name="widget" native="true">
<property name="geometry">
<rect>
<x>130</x>
<y>90</y>
**<width>161</width>**
<height>121</height>
</rect>
</property>
</widget>
Might that be part of the problem - the label is there, it is just outside of the painted area for the widget?