I want to disable resizing my form - here is what I have tried.
I have changed the resize policy of the form to the following
HorizontalPolicy:Fixed
VerticalPloicy: Fixed
I have also tried the following
Form *w = new Form();
w->setFixedSize(w->size());
w->show();
But the form still gets resized by dragging the corners. Any suggestions ?
It definitely has to be possible.
Firstly you should know, that before window is actually shown it has no information of it's size - so size will probably return 0 (or invalid; or anything ;) ) at this point - it would probably mess up entire sizing and is therefore silently rejected. I would try
Form *w = new Form();
//w->ensurePolished();
w->setFixedSize(w->sizeHint());
w->show();
Size hint should have correct value no matter what. QWidget::ensurePolished() might be necessary here, but I recommend trying first without it - if it works, why complicate things?
If it still doesn't work, then you can simply try overriding resizeEvent() and setting the only right size for your widget if user resizes it to anything else. This will still give user an illusion of resize-ability (cursors changes on the edges and so on), so it's really the last option.
EDIT:
#include <QtGui/QApplication>
#include <QWidget>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
w.setFixedSize(500,500);
w.show();
return a.exec();
}
Result: widget cannot be resized. So it is not change to QMainWindow that helped - oat least on my system a simple widget can do it too ;)
Related
Enabling a ticks for QSlider seems to mess up the sizeHint of the slider itself.
Consider this simple code:
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QSlider ds{Qt::Horizontal};
ds.setRange(0, 100);
ds.setTickPosition(QSlider::TicksAbove);
ds.setTickInterval(20);
ds.show();
return a.exec();
}
and this is how is rendered:
notice how the slider is cropped below.
this behaviour is the same in a complex widget too of course:
Resizing the window of the first slider tick position does not follow the slider itself.
So the question is how have a QSlider rendered properly with ticks enabled?
I would recommend to add VerticalSpacers at the top and bottom, which are set to "expanding" So that the slider is sandwiched. So when you resize the whole widget, for vertical changes th slider stays minimumHeight, but for horizontal changes it expands (at least this is what I expect what you want to achieve).
The practical way I found to solve this is to set the minimum size manually to the bare minumum to avoid the incorrect render:
ds.setMinimumHeight(30);
I understand setCentralWidget is required in QMainWindow implementation, and at first sight, it seemed extremely self-explaining what central widget means. But is there a more strict definition of "central"?
Say, I have several equally important widgets located in the central area of the window, should I always find a way to group them together and set the group to be the central widget? or I could just randomly choose one?
More importantly, what happens to the non-central widgets? Are there certain differences between central and non-central widgets that might impact their behaviors later?
The Qt documentation says nothing about this, other than simply stating central widget is important, which is not very helpful.
The central word in the setCentralWidget() method has nothing to do with the importance but if you check the layout that has the QMainWindow we will see that it is in the central position:
should I always find a way to group them together and set the group to be the central widget? Or I could just randomly choose one? There can only be one centralwidget, so if you want to have several widget in the central position you must create a new widget that is the container and set the other widget through the layouts.
what happens to the non-central widgets? Are there certain differences between central and non-central widgets that might impact their behaviors later? There's no difference.
Say in your central widget box above, I place two QLabels symmetrically with respect to the exact central point. In this case, which QLabel should be the central widget? Either one is fine?
You do not have to choose, you can the 2 QLabels be part of the centralWigdet, centralwidget only refers to the central position, for example:
#include <QtWidgets>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMainWindow w;
QLabel left_label("left");
left_label.setAlignment(Qt::AlignCenter);
QLabel right_label("rigth");
right_label.setAlignment(Qt::AlignCenter);
QWidget *central_widget = new QWidget;
QHBoxLayout *lay = new QHBoxLayout(central_widget);
lay->addWidget(&left_label);
lay->addWidget(&right_label);
w.setCentralWidget(central_widget);
w.show();
return a.exec();
}
If either widget is fine, why is setting central widget so critically required by QMainWindow?
You do not necessarily have to set a centralwidget, but QMainWindow unlike other widget already has a certain layout, so if you want to place the widgets you must use that method.
The centralwidget refers to a relative position but it is not exactly a central position:
#include <QtWidgets>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMainWindow w;
QLabel *central_widget = new QLabel("Central Widget");
central_widget->setAlignment(Qt::AlignCenter);
w.setCentralWidget(central_widget);
QDockWidget *dock = new QDockWidget("left");
w.addDockWidget(Qt::LeftDockWidgetArea, dock);
dock->setWidget(new QTextEdit);
w.show();
return a.exec();
}
Usually you don't need a QMainWindow!
If you don't need docking nor MDI, then don't use QMainWindow: a QWidget or a QDialog will do instead.
Central means "in the center", as in "in the middle", not as in "important!". QMainWindow's provides docking and multiple document interface (MDI) functionality, and there the notion of a central widget is useful. There can only be one central widget, so "which of many" should be made central is moot: you can't have more than one. One of the fundamental aspects of Qt object design is that QObject is a container of other objects, and so is a QWidget: it's a canvas that you can place other widgets on. So, if you absolutely need docking and/or MDI, then the central widget will be any QWidget that you put other non-docking widgets on. That' all.
I'm trying to build a simple memory game with Qt 5.11.1 and C++, where you get a few tiles on screen and you have to click on two and try to match the images they show.
My tiles are implemented as QPushButtons. Each time you click on one an image is displayed (by calling a showImage()method that changes the button background). When a second tile is clicked, if there is a match the two buttons are disabled so you can't click on them again (and you get a higher score). However, if you didn't get a match, the two tiles you just clicked will go back to their initial state (showing no image) after 1 second (this allows the user to "memorize" which image was showing up on each tile).
Whenever you click on a "tile" (button) it becomes disabled (button->setEnabled(false)). If after clicking a second tile there was no match, then both tiles are turned back and then setEnabled(true) again. I'm using a single shot QTimer to call the method that will turn back the tiles:
QTimer::singleShot(1000, this, SLOT(turnTilesBack()));
firstTile->setEnabled(true);
secondTile->setEnabled(true);
Everything is working as expected, except for one thing: as QTimer runs in its own thread (or so I understand from what I read) all of the available tiles remain enabled during the 1000 milisecond lapse, allowing the user to continue clicking on them. However, when there is no match, I'd like to "freeze" the buttons until the QTimer has timed out so the user can't continue playing until the tiles have turned back.
So instead of using the QTimer I've trying this solution which I saw on this question (How do I create a pause/wait function using Qt?):
QTime dieTime= QTime::currentTime().addSecs(1);
while (QTime::currentTime() < dieTime)
turnTilesBack();
although I removed this line: QCoreApplication::processEvents(QEventLoop::AllEvents, 100); as this would cause the main thread not to freeze and buttons would still be clickable.
But with this approach, whenever the user clicks on the second tile, if there is no match the image is not even displayed, even when my showImage() method is called before the code above, and I'm not sure why this is. So the user knows there was no match because after 1 second the tiles go back to their initial state, but they never got to see the image on the second button.
As another approach, I also though of disabling all buttons and then after the single shot QTimer times out, re-enabling back only the ones that have not been matched yet. But this would require additional logic to keep track of which tiles have been matched. So for now I'm sticking to the
Is there a cleaner solution? Maybe there's a way to make the QTimer freeze the main thread until it times out?
An easy way to enable/disable the entire group of QPushButtons is to place them on an intermediate widget (in the below example I've used a QFrame)
If you want to disable all the QPushButtons, you just disable the frame, and all its child widgets will be disabled.
When you want to re-enable them, you enable the frame.
Any widgets inside the frame which are already disabled won't be enabled when the frame is re-enabled, so you won't lose your enabled/disabled state on the individual buttons
Here is a simple example. Note that I've used explicit enable/disable buttons which act as a proxy for your timer.
#include <QApplication>
#include <QMainWindow>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QPushButton>
#include <QFrame>
int main(int argc, char** argv)
{
QApplication* app = new QApplication(argc, argv);
QMainWindow* window = new QMainWindow();
window->setFixedSize(1024, 200);
QWidget* widget = new QWidget();
QHBoxLayout layout(widget);
QPushButton* enable = new QPushButton("enable");
QPushButton* disable = new QPushButton("disable");
QFrame* frame = new QFrame();
layout.addWidget(enable);
layout.addWidget(disable);
layout.addWidget(frame);
QVBoxLayout frame_layout(frame);
for (int i = 0; i < 5; ++i)
frame_layout.addWidget(new QPushButton("click"));
// this shows that an already disabled button remains disabled
QPushButton* already_chosen = new QPushButton("click");
frame_layout.addWidget(already_chosen);
already_chosen->setEnabled(false);
QObject::connect(enable, &QPushButton::clicked, [&]{ frame->setEnabled(true); });
QObject::connect(disable, &QPushButton::clicked, [&]{ frame->setEnabled(false); });
window->setCentralWidget(widget);
window->show();
return app->exec();
}
This is a very simple problem to reproduce. Create a new project with Qt Creator with a QMainWindow. Using designer add a single widget (it doesn't matter which one) and then use the right button to set a layout (any layout as with a single widget the results are always the same).
There will be a gray border around the widget. I would like to remove this border so that the widget occupies the entirety of the main window area (which Qt always names centralWidget). Basically the single widget is all I want to see.
Is this possible? If so, how?
Yes, it's possible. All you need is setting margins of that centralWidget to 0. (note that you should first set up a layout)
In properties panel set the following properties to 0.
layoutLeftMargin
layoutTopMargin
layoutRightMargin
layoutBottomMargin
Also note that using a QWidget (not QMainWindow) as your main app window is perfectly valid, so if your app has only one widget, you won't need a QMainWindow at all. It's enough to show that widget.
The answer above is the right answer but I also wanted to share what I've found out. I basically wanted to create a QGraphcisView that occupies the entire screen. and I thought of the above method, which Hi I'm Frogatto answered. Another way is to create a simple app with this code:
#include <QCoreApplication>
#include <QApplication>
#include <QGraphicsView>
int main(int argc, char *argv[])
{
//QCoreApplication a(argc, argv);
QApplication app(argc, argv);
QGraphicsView *view = new QGraphicsView();
view->showFullScreen();
return app.exec();
}
And this .pro file:
QT += core gui widgets
CONFIG += c++11
TARGET = Test
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp
This also does what I wanted!. Maybe it can help someone.
How to apply the design of window frame?
Not Qt::FramelessWindowHint , but Windows 7 frame
edit:
How to create your own frame in QStyle?
If you talk about frame style, it will be good solution.
#include <QtGui/QApplication>
#include <QWindowsStyle>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setStyle(new QWindowsStyle);
MainWindow w;
w.show();
return a.exec();
}
But Qt has many other styles - learn about QMotifStyle and QCleenlooksStyle... [link]
You can try Coffe or Pagefold styles.
You can set a style sheet on an individual child widget, on a whole window, or even on a whole application by calling QWidget::setStyleSheet() or QApplication::setStyleSheet().
Frames are usually the business of the windowing system and cannot be freely re-styled by the application. You'd probably need to create a frameless window with mentioned hint and paint your own title bar/frame inside the widget.