Qt button not appearing in main window - c++

(Note: I started learning Qt yesterday and I did my search before asking this.)
After a bit of playing with Qt Designer I decided to make a more serious program, all programatically. Whereas before, simple taskes seemed.. simple, now, diaplaying a button is hell of a complicated because it doesn't show up.
main.cpp
int main(int argc, char * argv[])
{
QApplication app(argc, argv);
PixelPeep p;
p.show();
return app.exec();
}
pixelpeep.h - relevant part
class PixelPeep : public QMainWindow
{
Q_OBJECT
public:
explicit PixelPeep(QWidget *parent = 0);
signals:
public slots:
private:
QToolBar * toolBar;
QHBoxLayout * toolbarLayout;
QToolButton * addButton; // add new image
QScrollBar * zoomBar;
};
pixelpeep.cpp - relevant part
PixelPeep::PixelPeep(QWidget *parent) :
QMainWindow(parent)
{
resize(600,375);
toolBar = new QToolBar;
addButton = new QToolButton;
addButton->setGeometry(20,20,20,20);
toolBar->addWidget(addButton);
toolbarLayout = new QHBoxLayout;
toolbarLayout->addWidget(addButton);
}
After all this, I get an empty window.
Possible cause, AFAIK:
button would go out of scope after being created in the class constructor - it's not the case here because it's dynamically allocated and pointer by the private member addButton
not being in a layout or having size 0 - it's not the case since both of these were addressed in the code
What else could it be?
Sorry for such a noob question...

Call addToolBar(toolBar); inside the PixelPeep constructor.
You didn't set any icon on your button so it will appear as invisible. Hover over it and you will see it's there:

Related

It it right way to user a global QObject for cross signal/slot forward

My situation is, a big Qt project with many QWidget communication requirement.
For example, I've a QPushButton B and a QLabel L, I need to click thd button B to show some text on label L or hide it, etc. But the problem is neither of them can get each other's object pointer, because both of them located in a deep QWidget tree, maybe their grandgrandgrand parent widget was sibling, what ever.
So my option, is creating a global unique QObject, just for singal/slot forwad,like this:
class GlobalForward: public QObject
{
Q_OBJECT
public:
GlobalForward():QObject(null) {}
signal:
void SigForwardButton(bool toggle);
}
GlobalForward* gForwardObj;
int main(int argc, char* argv[])
{
QApplication app(argc, argv[]);
gForwardObj = new GlobalForward();
QWidget w;
QPushButton* button = new QPushButton(&w);
QWidget m;
QLabel* label = new QLabel(&m);
w.show();
m.show();
connect(button, &QPushButton::clicked, gForwardObj, &GlobalForward::SigForwardButton);
connect(gForwardObj, &GlobalForward::SigForwardButton, label, &QWidget::hide);
return app.exec();
}
Actually, the button and the label are so faraway that they cannot see each other. I want to use GlobalForward to concat the singnal to make it work . Further more, it can forwad QEvent silmiarly.
What I want to know is, is this way properly solved my problem, and what's the disadvantage of it. Also, any better solution will be appropriate, thanks.

Switching between windows. Qt Widgets ( 1 widget in memory )

For example I have 2 widgets and I press button on first widget. I need to delete first widget and create new widget.
How is it possible? I mean some structure for this. I used stackedwidgets, but pages from stackedwidgets located in memory. I need to avoid this.
void Window::on_registrationButton_clicked(){
ui->logWindow->hide();
ui->RegistrWindow->show();
}
As you are going to eliminate the object you can not do it within the same class the object belongs to, you have to do it outside of it, for example in the following code I created a signal that is triggered when the button is pressed, this I have connected it to a lambda function where the new object is created and the object that emits it is eliminated.
class LogWindow: public QWidget{
Q_OBJECT
public:
LogWindow(const QString &text, QWidget *parent=Q_NULLPTR):QWidget(parent){
setLayout(new QVBoxLayout);
btn = new QPushButton(text, this);
layout()->addWidget(btn);
connect(btn, &QPushButton::clicked, this, &LogWindow::customSignal);
}
signals:
void customSignal();
private:
QPushButton *btn;
};
class RegWindow : public QWidget{
[...]
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
LogWindow *log= new LogWindow("LogWindow");
RegWindow *reg;
QObject::connect(log, &LogWindow::customSignal, [&reg, &log](){
reg = new RegWindow("RegWindow");
reg->show();
log->deleteLater();
});
log->show();
return a.exec();
}
#include "main.moc"
The complete example can be found in the following link

How to hide a temporary search bar?

I have a window that contains a browser. Up is a toolbar. In the bottom of the window is a search bar.
Search bar has a close button [x].
When the user clicks the close button I want the bar to disappear.
I want the bar only appear when user press CTRL + F. I tried to connect the close butoon with .hide() command, but application crashes. I need help.
.cpp
DocumentationWin::DocumentationWin (QWidget * parent){
docs = new QTextBrowser( this );
//Prepare toolbar
toolbar = new QToolBar( this );
//add stuff to toolbar
//Prepare footer bar
searchlabel = new QLabel(tr("Find in page:"),this);
resultslabel = new QLabel("",this);
searchinput = new QLineEdit();
findprev = new QToolButton(this);
findprev->setArrowType(Qt::UpArrow);
connect(findprev, SIGNAL(clicked()), this, SLOT (clickFindPrev()));
findnext = new QToolButton(this);
findnext->setArrowType(Qt::DownArrow);
connect(findnext, SIGNAL(clicked()), this, SLOT (clickFindNext()));
QStyle *style = qApp->style();
QIcon closeIcon = style->standardIcon(QStyle::SP_TitleBarCloseButton);
QPushButton *closeButton = new QPushButton(this);
closeButton->setIcon(closeIcon);
closeButton->setFlat(true);
connect(closeButton, SIGNAL(clicked()), this, SLOT (clickCloseFind()));
QWidget *bottom = new QWidget;
QHBoxLayout *footer = new QHBoxLayout();
casecheckbox = new QCheckBox(tr("Case sensitive"),this);
footer->setContentsMargins(5,5,5,5);
footer->addWidget(searchlabel);
footer->addSpacing(3);
footer->addWidget(searchinput);
footer->addWidget(findprev);
footer->addWidget(findnext);
footer->addSpacing(10);
footer->addWidget(casecheckbox);
footer->addSpacing(10);
footer->addWidget(resultslabel);
footer->addStretch(1);
footer->addWidget(closeButton);
bottom->setLayout(footer);
//Prepare main layout
layout = new QVBoxLayout;
layout->setContentsMargins(0,0,0,0);
layout->setSpacing(0);
layout->addWidget(toolbar);
layout->addWidget(docs);
layout->addWidget(bottom);
this->setLayout(layout);
this->show();
}
void DocumentationWin::clickCloseFind(){
bottom->hide();
}
.h
class DocumentationWin : public QDialog
{
Q_OBJECT
public:
DocumentationWin(QWidget * parent);
protected:
virtual void keyPressEvent(QKeyEvent *);
private slots:
void clickCloseFind();
private:
QVBoxLayout* layout;
QToolBar* toolbar;
QTextBrowser* docs;
QBoxLayout* footer;
QLabel *searchlabel;
QLabel *resultslabel;
QLineEdit *searchinput;
QToolButton *findprev;
QToolButton *findnext;
QCheckBox *casecheckbox;
QWidget *bottom;
QPushButton *closeButton;
};
Ahh, the classic case of local variables hiding the members. There have been quite a few identical questions on SO about this. This is wrong:
QWidget *bottom = new QWidget;
You want:
bottom = new QWidget;
You'll run into these problems always because you dynamically allocate all the widgets - that's completely unnecessary.
Suggestions:
Hold the child widgets and layouts by value, don't dynamically allocate them.
Don't pass a parent to widgets that are managed by a layout. Every widget that is laid out will be automatically parented.
Don't redundantly call setLayout. A QLayout takes the widget to lay its children on as a constructor argument.
QWidget::hide() is a slot.
Many widgets take the text as a constructor argument.
If you don't have any arguments to pass to the constructor in a new expression, you can drop the parentheses (but we try to avoid these anyway):
searchinput = new QLineEdit; // not QLineEdit();
Widgets shouldn't usually show() themselves upon construction. No Qt widget does that. It's up to the widget's user to do it.
C++ overloads a method call syntax with construction syntax. To differentiate the two, prefer uniform initialization (Type{arg0, arg1, ...}) over old syntax that used ().
Here's how your code can look when you're using C++11. This compiles with either Qt 4 or Qt 5. If you don't target Qt 4, you should be using the new connect syntax, though.
As you can see, there isn't a single explicit dynamic allocation - that's how quite a bit of C++11 code will look, when the used types are sane.
// https://github.com/KubaO/stackoverflown/tree/master/questions/find-hide-38082794
#include <QtGui>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtWidgets>
#endif
class DocumentationWin : public QDialog
{
Q_OBJECT
public:
explicit DocumentationWin(QWidget * parent = 0);
private:
QVBoxLayout layout{this};
QToolBar toolbar;
QTextBrowser docs;
QWidget bottom;
QHBoxLayout footer{&bottom};
QLabel searchlabel{tr("Find in page:")};
QLabel resultslabel;
QLineEdit searchinput;
QToolButton findprev;
QToolButton findnext;
QCheckBox casecheckbox{tr("Case sensitive")};
QPushButton closeButton;
Q_SLOT void onFindPrev() {}
Q_SLOT void onFindNext() {}
};
DocumentationWin::DocumentationWin(QWidget * parent) : QDialog(parent) {
findprev.setArrowType(Qt::UpArrow);
connect(&findprev, SIGNAL(clicked()), this, SLOT(onFindPrev()));
findnext.setArrowType(Qt::DownArrow);
connect(&findnext, SIGNAL(clicked()), this, SLOT(onFindNext()));
auto style = qApp->style();
auto closeIcon = style->standardIcon(QStyle::SP_TitleBarCloseButton);
closeButton.setIcon(closeIcon);
closeButton.setFlat(true);
connect(&closeButton, SIGNAL(clicked(bool)), &bottom, SLOT(hide()));
footer.setContentsMargins(5,5,5,5);
footer.addWidget(&searchlabel);
footer.addSpacing(3);
footer.addWidget(&searchinput);
footer.addWidget(&findprev);
footer.addWidget(&findnext);
footer.addSpacing(10);
footer.addWidget(&casecheckbox);
footer.addSpacing(10);
footer.addWidget(&resultslabel);
footer.addStretch(1);
footer.addWidget(&closeButton);
layout.setContentsMargins(0,0,0,0);
layout.setSpacing(0);
layout.addWidget(&toolbar);
layout.addWidget(&docs);
layout.addWidget(&bottom);
}
int main(int argc, char ** argv) {
QApplication app{argc, argv};
DocumentationWin win;
win.show();
return app.exec();
}
#include "main.moc"

How to add a Menu Bar into a Window Frame? [QT with C++]

I'm a beginner in C++ and I started learning how to use QT components through code at MVS IDE. I still don't know if that was the best option to begin, but since I'm a java programmer, I made the path I made with Java (Swing components). So, my problem is, how to comunicate two class of my code, since in one I made the window frame and in the other I made my menu bar?
In java I would make something like:
JFrame frame = new JFrame();
JMenu menu = new JMenu();
frame.add(menu);
Anyway, This is my code:
#include "Header.h"
class MainWindow{
private:
QWidget *widget;
public:
void buildWindow(QApplication& app){
widget = app.desktop();
QMainWindow *main_window = new QMainWindow();
QWidget *mainWid = new QWidget(main_window);
MyMenuBar myMenuBar(mainWid);
main_window->setWindowState(mainWid->windowState() | Qt::WindowMaximized);
main_window->setWindowTitle("QT Trainning");
main_window->show();
}
};
class MyMenuBar:QMainWindow {
public:
MyMenuBar(QWidget* mainWid){
QAction *quit = new QAction("&Quit", this);
QMenuBar *menu = new QMenuBar(mainWid);
QMenu *file;
menu->addMenu(file);
file = menuBar()->addMenu("&File");
file->addAction(quit);
connect(quit, SIGNAL(triggered()), qApp, SLOT(quit()));
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow frame;
frame.buildWindow(app);
return app.exec();
}
I tryed to create an Instance of MenuBar inside the Window class but wans't so helpfull and to be honest most of the materials I found to deal with QT interface they supose that you are using the QT GUI...Any tips about how to solve the problem or what should I really do to practice C++??
Thanks in advance
You should specify access specifier for inheritance,otherwise default mode is public.
Also, if you are going to have all the classes in the same file the ordering is important(i think). In your case MyMenuBar should come before MainWindow. So, it is a better practice to have different components in different headers and then include them as necessary.
Here is the code for the case where you need two classes separately:
class TrainingMenu:public QMainWindow {
public:
TrainingMenu(QMenuBar *menubar){
QAction *quit = new QAction("&Quit", menubar);
QMenu *file;
file = menubar->addMenu("&File");
file->addAction(quit);
connect(quit, SIGNAL(triggered()), qApp, SLOT(quit()));
}
};
class MainWindows:public QMainWindow{
private:
TrainingMenu* _menu;
public:
MainWindows(QMainWindow *parent = 0):QMainWindow(parent) {
_menu=new TrainingMenu(MainWindows::menuBar());
this->setWindowTitle("Qt training");
this->setWindowState(Qt::WindowMaximized);
this->show();
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindows window;
return app.exec();
}
This example should be good enough. You do the following:
Create a QMenu with the top widget as a parent
Add submenu QMenu instances to the root level menu

Why is QHBoxLayout causing widgets to overlap?

I need to place several instances of a custom QPushButton subclass adjacent to one another. For some reason, the buttons overlap one another when painted. A simplified example of the problem is below.
Here is the (incorrect) output:
Here is the code:
#include <QtGui>
class MyButton : public QPushButton {
public:
explicit MyButton(Qt::GlobalColor color, QWidget *parent = NULL)
: QPushButton(parent), color_(color) {
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
}
QSize sizeHint() const {
return QSize(50, 25);
}
protected:
void paintEvent(QPaintEvent *) {
QPainter painter(this);
painter.setOpacity(0.5);
painter.fillRect(0, 0, width(), height(), color_);
}
private:
Qt::GlobalColor color_;
};
int main(int argc, char **argv) {
QApplication app(argc, argv);
QWidget widget;
QHBoxLayout *layout = new QHBoxLayout;
layout->setSpacing(0);
MyButton *w1 = new MyButton(Qt::red);
MyButton *w2 = new MyButton(Qt::green);
MyButton *w3 = new MyButton(Qt::blue);
layout->addWidget(w1);
layout->addWidget(w2);
layout->addWidget(w3);
widget.setLayout(layout);
widget.show();
return app.exec();
}
What is causing this, and how do I fix it? BTW, I tried something similar with regular QWidget subclasses (instead of QPushButton subclasses), and there is no problem. It is something peculiar to QPushButton.
UPDATE: I'm really thinking now that this is a bug. I submitted it to the Qt Bug Tracker; we'll see what the Trolls think. In any case, deriving from QAbstractButton fixes the drawing problem ... I just had to re-implement some of the functionality I needed.
UPDATE 2: The Trolls at Qt provided a solution (workaround?); I posted their fix as an answer below. I'm leaving it up to their team to determine if this is a feature or bug. It apparently only behaves differently on the Mac.
The solution is to add the following to the subclass:
setAttribute(Qt::WA_LayoutUsesWidgetRect);
Apparently it is only necessary on the Mac platform; Windows and Linux display the layout as expected.
Instead of calling setSizePolicy() and reimplement sizeHint(), I would try to simply call
setFixedSize(50, 25)
in your constructor. This should update the sizeHint on its own.
Hope this helps.
Your code works fine for me. I have tested it. What version you use? I use Qt 4.6.3 and it is fine.