showing hidden dockwidget in qt - qt

hi i create a dockwidget which i am starting it as hidden. The problem is that afterwards i cannot show it, while i can get the status correctly from the isHidden() function. The weird thing is that if i start the dockwidget not hidden, it works perfect. I am including an example that reproduces this strange behaviour.
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtGui>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void showDock();
private:
Ui::MainWindow *ui;
QDockWidget *dock;
QPushButton *button;
};
#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);
// QMainWindow mainWindow;
// QDockWidget *dock = new QDockWidget(&mainWindow);
QDialog *dockDialog = new QDialog(this); // <---------edit: you need to create a parent widget for the dock
dock = new QDockWidget(dockDialog);
dock->setStyleSheet("QDockWidget { font: bold }");
dock->setFloating(true);
dock->setFeatures(QDockWidget::DockWidgetVerticalTitleBar | QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable);
QAbstractButton *floatButton = dock->findChild<QAbstractButton*>("qt_dockwidget_floatbutton");
if(floatButton)
floatButton->hide();
dock->setAllowedAreas( Qt::NoDockWidgetArea );
dock->setWindowTitle("Tools");
this->addDockWidget(Qt::TopDockWidgetArea, dock, Qt::Vertical);
QMainWindow *window = new QMainWindow(dock); // <------edit: set the dock to be the parent for the window
window->setWindowFlags(Qt::Widget);
QToolBar *bar = new QToolBar(window);
bar->setMovable(false);
bar->addAction("Select");
bar->addAction("Polygon");
bar->addAction("Brush");
bar->addAction("Erazer");
bar->addSeparator();
bar->addAction("Mark");
bar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
bar->setOrientation(Qt::Vertical);
window->addToolBar(Qt::LeftToolBarArea, bar);
window->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
window->setParent(dock);
dock->setWidget(window);
dock->hide(); // <------------ comment this line and it will work, edit: you do not need to do that anymore, it is working nicely now
button = new QPushButton("show", this);
button->setCheckable(true);
QObject::connect(button, SIGNAL(clicked()), this, SLOT(showDock()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::showDock()
{
// qDebug() << "hello";
if(button->isChecked()){
if(dock->isHidden()){
qDebug() << "hidden";
dock->setFloating(true); // <-----edit: you need to add these lines in order to be able to see the dialog that contains the dock widget, i do not know why i need to that again since in the initialization i already specifying that my dock is floatable
QAbstractButton *floatButton = dock->findChild<QAbstractButton*>("qt_dockwidget_floatbutton"); // <---------edit: add this lines in order to get rid off the floating button
if(floatButton)
floatButton->hide(); // <----edit: the same as previous
dock->show();
}
}
if(!button->isChecked()){
if(!dock->isHidden()){
qDebug() << "not hidden";
dock->hide();
}
}
}
as it is now the above code the dockwidget is not appearing in the screen. If you try to comment the line that i am specifying in the mainwindow.cpp it works, but the point is that i want to start the dockwidget hidden. Does someone have any idea, of what is happening.
Thanks.

Parent of the QDock control should be your window widget, and not object of the MainWindow class.
So, you need to replace this:
dock = new QDockWidget(this);
with this:
QMainWindow *window = new QMainWindow(0); // I smell a potential leak here (set the parent!)
dock = new QDockWidget(window);
Control is visible when you press Show button in the first case, too, but it is somewhere outside the window, so you may not see it. Also, there is no need to create separate instance of QMainWindow inside class that is already inheriting QMainWindow.

I see you show()/hide() your dockwidget. I haven't tried it myself but maybe you should hide and show the dockwdiget with the QDockWidget::toggleViewAction method.

Related

QGraphicsSceneMouseEvent get position will not work [duplicate]

This question already has an answer here:
Qt Widgets and derived classes
(1 answer)
Closed 3 years ago.
I am trying to make an application with a QGraphicsView in it. I tried to get the position of a mouse when the mouse was pressed with QGraphicsSceneMouseEvent, but it doesn't seem to work. The entire function is never called when I press the mouse.
I would like to make an application that can load an image into the QGraphicsView and then when you press the mouse button, it should add a small circle.
This is my code:
dialog.cpp:
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
ui->graphicsView = new GraphicsView();
}
Dialog::~Dialog()
{
delete ui;
}
graphicsview.h:
#ifndef GRAPHICSVIEW_H
#define GRAPHICSVIEW_H
#include <QGraphicsView>
#include <QMouseEvent>
#include <QDebug>
class GraphicsView : public QGraphicsView
{
public:
GraphicsView();
protected:
void mousePressEvent(QMouseEvent *event) override;
private:
QGraphicsScene *scene;
};
#endif // GRAPHICSVIEW_H
graphicsview.cpp:
#include "graphicsview.h"
GraphicsView::GraphicsView()
{
scene = new QGraphicsScene();
this->setScene(scene);
}
void GraphicsView::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
{
qDebug() << "The left button was pressed!";
}
}
You're almost there.
Just change GraphicsView::GraphicsView() to:
GraphicsView::GraphicsView(QWidget *parent=nullptr) : QGraphicsView(parent) {}
and change ui->graphicsView = new GraphicsView(); to
QVBoxLayout *verticalLayout = new QVBoxLayout(this);
verticalLayout->addWidget(new GraphicsView(this));
This will make the graphics view a parent of the dialog. Make sure that your dialog doesn't have anything in it when you add the code above. Alternatively, you can add a vertical layout to the dialog in your dialog.ui file and do
ui->verticalLayout->addWidget(new GraphicsView(this));
I believe that solves your problem. Respond if you still have any issues.
Make sure you always have a parent parameter. Without it, you're not telling your program where it's supposed to add your widget.

Reparenting a Qt widget

I have a WidgetA widget, which is an owner-drawn widget. It's currently placed in QMainWindow's QVBoxLayout. After clicking a button, I'd like to "detach" WidgetA from this QVBoxLayout, insert QSplitter into this QVBoxLayout and "readd" WidgetA to this QSplitter. All this without destroying WidgetA, so it will preserve its drawing context, etc.
So, currently I have this (only one widget in a window):
I'd like to put a QSplitter between WidgetA and QMainWindow, and create a new widget, WidgetB, so I'd end up with:
Later I'd like it to split even further, so both WidgetA and WidgetB would still allow themselves to be detached and placed in a new QSplitter, so it would be possible to create f.e. this hierarchy:
And, to be complete, one more step:
I'm not very experienced in Qt, so what I'm trying to do may seem pretty obvious, but I couldn't find how to "reparent" widgets. Is this possible in Qt?
Please, see reparent example, may be it helps you:
//MyMainWindow.h
#include <QWidget>
#include <QPainter>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QSplitter>
class MyWidget: public QWidget
{
public:
MyWidget(QWidget* parent, int number)
: QWidget(parent),
m_number(number)
{
}
private:
virtual void paintEvent(QPaintEvent* e)
{
QWidget::paintEvent(e);
QPainter p(this);
p.fillRect( rect(), Qt::red);
p.drawText( rect(), Qt::AlignCenter, QString::number(m_number) );
}
private:
int m_number;
};
class MyMainWindow: public QWidget
{
Q_OBJECT
public:
MyMainWindow()
{
setFixedSize(300, 200);
m_mainLayout = new QVBoxLayout(this);
QHBoxLayout* buttonLayout = new QHBoxLayout;
m_mainLayout->addLayout(buttonLayout);
m_button = new QPushButton("Button", this);
buttonLayout->addWidget(m_button);
connect(m_button, SIGNAL(clicked()), this, SLOT(onButtonClickedOnce()));
m_initWidget = new MyWidget(this, 1);
m_mainLayout->addWidget(m_initWidget);
}
private slots:
void onButtonClickedOnce()
{
m_button->disconnect(this);
m_mainLayout->removeWidget(m_initWidget);
QSplitter* splitter = new QSplitter(Qt::Horizontal, this);
m_mainLayout->addWidget(splitter);
splitter->addWidget(m_initWidget);
MyWidget* newWidget = new MyWidget(splitter, 2);
splitter->addWidget(newWidget);
}
private:
QVBoxLayout* m_mainLayout;
QWidget* m_initWidget;
QPushButton* m_button;
};
//main.cpp
#include <QtWidgets/QApplication>
#include "MyMainWindow.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyMainWindow mainWindow;
mainWindow.show();
return a.exec();
}
When you operate with widget which is part of layout, then you need to use appropriate methods of QLayout (parent of QVBoxLayout) to detach the item from layout:
QLayout::removeWidget (removeItem if it is not widget, but spacer item or another layout)
QLayout::addWidget (addItem --/--)
Btw: even when widget moves between layouts, its parent may even stay same. I guess you have no need to call QWidget::setParent() as the calls of addWidget/removeWidget will do all work for you.

Exit Application in Qt

I have built an app in Qt that contains two buttons: an exit button and an import button. When the import button is pushed, a list of buttons is shown in a scrollarea on the screen (the file loggers.csv contains the data 1;2;3;4;5;).
It all works fine, but when I push the exit button (which of course should close everything), the app is not stopped properly (the stop button of Qt is still active, and the play button isn't). When I run the debugger and push the exit button it gives an error: Invalid address specified to RtlFreeHeap( 0ADF0000, 0028FE40 ). Can anybody help me?
main
#include <QtGui/QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.showFullScreen();
return a.exec();
}
Mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtGui>
#include "logger.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
QPushButton exit_btn;
QPushButton import_btn;
private slots:
void createMenus();
void exit();
void import();
private:
int window_width;
int window_height;
int numLoggers;
int numSelected;
QVector<Logger*> loggers;
QScrollArea * scroll_area;
QVBoxLayout scrollLayout;
QWidget viewport;
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
Mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QtGui"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
window_width = QApplication::desktop()->width();
window_height = QApplication::desktop()->height();
createMenus();
connect(&exit_btn,SIGNAL(clicked()),this,SLOT(exit()));
connect(&import_btn,SIGNAL(clicked()),this,SLOT(import()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::createMenus()
{
import_btn.setParent(ui->centralWidget);
import_btn.setGeometry(400,300,100,100);
import_btn.setText("IMPORT");
exit_btn.setText("EXIT");
exit_btn.setParent(ui->centralWidget);
exit_btn.setGeometry(window_width-50,12,32,32);
viewport.setLayout(&scrollLayout);
viewport.resize(0,0);
scroll_area = new QScrollArea(ui->centralWidget);
scroll_area->setGeometry(0,66,317,window_height-116);
scroll_area->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
scroll_area->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
scroll_area->setWidget(&viewport);
scroll_area->setGeometry(0,97,317,window_height-228);
scrollLayout.setMargin(0);
scrollLayout.setSpacing(0);
}
void MainWindow::exit()
{
close();
qApp->quit();
}
void MainWindow::import()
{
numSelected=0;
QFile f("Loggers3.csv");
if (f.open(QIODevice::ReadOnly))
{
numLoggers=0;
QString data;
data = f.readAll();
QStringList vals = data.split(';');
while(vals.size()>=1)
{
Logger * logger = new Logger;
logger->setNumber(vals[0].toInt());
vals.removeAt(0);
loggers<<logger;
numLoggers++;
}
f.close();
for(int i=0; i<numLoggers;i++)
{
loggers[i]->createButtons();
scrollLayout.addWidget(loggers[i]->button);
}
viewport.resize(367,numLoggers*60);
}
}
logger.h
#ifndef LOGGER_H
#define LOGGER_H
#include <QtGui>
class Logger : public QWidget
{
Q_OBJECT
public:
explicit Logger(QWidget *parent = 0);
~Logger();
int number;
QLabel num;
QToolButton * button;
bool checked;
signals:
public slots:
void setNumber(int number);
void createButtons();
};
#endif // LOGGER_H
logger.cpp
#include "logger.h"
#include <QtGui>
Logger::Logger(QWidget *parent) :
QWidget(parent)
{
button = new QToolButton;
button->setCheckable(true);
button->setMinimumSize(317,60);
button->setStyleSheet("QToolButton{background-image: url(images/btn_bg); border:none}");
}
Logger::~Logger()
{
}
void Logger::setNumber(int logNumber)
{
number=logNumber;
}
void Logger::createButtons()
{
QLayout * layout = new QHBoxLayout;
QSpacerItem *spacer = new QSpacerItem(120, 31, QSizePolicy::Maximum, SizePolicy::Maximum);
num.setStyleSheet("color: white; font: bold 16px");
num.setText(QString::number(number));
layout->addWidget(&num);
layout->addItem(spacer);
button->setLayout(layout);
}
I'm not entirely certain about what you are trying to achieve... but your problem lies with these two lines:
viewport.setLayout(&scrollLayout);
viewport.resize(0,0);
In the documentation for the QWidget class it states that:
If there already is a layout manager installed on this widget, QWidget
won't let you install another. You must first delete the existing layout manager (returned by layout()) before you can call setLayout() with the new layout.
This is where your problem lies. Don't believe me, add this check before those two lines of code.
if(layout()){
qDebug() << "Another layout exists";
}
Source: QVBoxLayout Class Reference
The QVBoxLayout class lines up widgets vertically.
This class is used to construct vertical box layout objects. See QBoxLayout for details.
The simplest use of the class is like this:
QWidget *window = new QWidget;
QPushButton *button1 = new QPushButton("One");
QPushButton *button2 = new QPushButton("Two");
QPushButton *button3 = new QPushButton("Three");
QPushButton *button4 = new QPushButton("Four");
QPushButton *button5 = new QPushButton("Five");
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(button1);
layout->addWidget(button2);
layout->addWidget(button3);
layout->addWidget(button4);
layout->addWidget(button5);
window->setLayout(layout);
window->show();
First, we create the widgets we want in the layout. Then, we create the QVBoxLayout object and add the widgets into the layout. Finally, we call QWidget::setLayout() to install the QVBoxLayout object onto the widget. At that point, the widgets in the layout are reparented to have window as their parent.
Critical source of error in your project:
Widgets should be constructed on the heap because they will be deleted automatically when their parents are deleted. You have a custom widget class that you instantiate on the heap. The members should also go on the heap. Also, you should consider using the parent /child hierarchy in your GUI code to ensure proper memory management and proper deletion.
In my experience, if your program stops in RtlFreeHeap it is a good sign of memory corruption.
When calling
import_btn.setParent(ui->centralWidget);
centralWidget takes ownership of import_btn. That means, when centralWidget is deleted (which happens as part of delete ui;in your MainWindow's destructor), it will call delete on your member variable!
This leads to the reported memory corruption.
You need to allocate your QPushButton's dynamically, not as a plain member variable. So make them QPushButton*.
Here's how I did it from mainwindow.cpp, thanks to and this question: How to create a correct exit button in qt
QPushButton * quit_btn = new QPushButton(this);
quit_btn->setGeometry(540,440,93,27);
quit_btn->setText("Exit");
QObject::connect(quit_btn,SIGNAL(clicked()),qApp,SLOT(quit()));
Works flawlessly :D

Adding drop down menu to Qt GUI - error 'menubar' no declared

I'm trying to create a menu in Qt following this example http://doc.qt.nokia.com/latest/mainwindows-menus.html
but I keep getting the error 'menuBar' not declared in this scope
void Window::createMenus()
{
saveMenu = menuBar()->addMenu("&Save");
}
In context:
#include <QtGui>
#include "borderlayout.h"
#include "window.h"
Window::Window()
{
QTextBrowser *centralWidget = new QTextBrowser;
//***Change this to whatever widget(s) the drawing area is. QPainter or something?
centralWidget->setPlainText(tr("DRAW HERE YAY"));
BorderLayout *layout = new BorderLayout;
layout->addWidget(centralWidget, BorderLayout::Center);
layout->addWidget(createLabel("File ..."), BorderLayout::North);
layout->addWidget(createLabel("Toolbar yo!"), BorderLayout::West);
//layout->addWidget(createLabel("Status bar"), BorderLayout::South);
//Maybe we could put in a status bar. For now let's not worry about it. It's not a requirement.
setLayout(layout);
createMenus();
setWindowTitle(tr("Border Layout"));
}
QLabel *Window::createLabel(const QString &text)
{
QLabel *label = new QLabel(text);
label->setFrameStyle(QFrame::Box | QFrame::Raised);
return label;
}
void Window::createMenus()
{
saveMenu = menuBar()->addMenu("&Save");
}
window.h
#ifndef WINDOW_H
#define WINDOW_H
#include <QWidget>
class QLabel;
class QMenu;
class Window : public QWidget
{
Q_OBJECT
public:
Window();
private:
void createMenus();
QLabel *createLabel(const QString &text);
QMenu *saveMenu();
};
#endif
window.cpp
#include <QtGui>
#include "borderlayout.h"
#include "window.h"
Window::Window()
{
QTextBrowser *centralWidget = new QTextBrowser;
//***Change this to whatever widget(s) the drawing area is. QPainter or something?
centralWidget->setPlainText(tr("DRAW HERE YAY"));
BorderLayout *layout = new BorderLayout;
layout->addWidget(centralWidget, BorderLayout::Center);
layout->addWidget(createLabel("File ..."), BorderLayout::North);
layout->addWidget(createLabel("Toolbar yo!"), BorderLayout::West);
//layout->addWidget(createLabel("Status bar"), BorderLayout::South);
//Maybe we could put in a status bar. For now let's not worry about it. It's not a requirement.
setLayout(layout);
createMenus();
setWindowTitle(tr("Border Layout"));
}
QLabel *Window::createLabel(const QString &text)
{
QLabel *label = new QLabel(text);
label->setFrameStyle(QFrame::Box | QFrame::Raised);
return label;
}
void Window::createMenus()
{
saveMenu = menuBar()->addMenu("&Save");
}
The menu bar is a feature of the QMainWindow class.
Because your Window class is being inherited directly from QWidget, it does not have the menuBar method, hence your error.
You need to subclass your Window class from QMainWindow rather than QWidget.

how to add menu dynamically in Qt

I want to add, submenu to a menu item dynamically. How can I achive this?
I tried like this,
I have created an Action and submenu. Then I have added the submenu to action.
But, I have connected the “triggered” signal of action. its getting crash if I click on the action..
I have also handled the “aboutToShow” signal of menu, same its also getting crash when I click on action..
Here is the sampe code.
Submenu = new QMenu(this);
connect(Submenu, SIGNAL( aboutToShow()), this, SLOT(move ()));
QAction *test = new QAction(tr("Selection"), this);
test ->setMenu(Submenu);
menubar()->addAction(test);
I want to get the notification, before the display of submenu..
additonal information:
pleas try this code, in your main window constructor.
QAction *action = new QAction("Test",this);
QAction *dummyaction = new QAction("Testing",this);
QMenu *menu = new QMenu();
menu->addAction(dummyaction);
bool val= connect(menu, SIGNAL( aboutToShow()), this, SLOT( Move()));
val= connect(menu, SIGNAL( aboutToHide()), this, SLOT(Move()));
action->setMenu(menu);
this->menuBar()->addAction(action);
if I do like this, I am able to see one submenu item. But before that Move slot should call, its not getting called.. and even before hide also the same slot should call.. its not coming..
I tried the return values of connect.. its true only… so what is wrong with my code.. please say..
Such code should work:
QMainWindow wnd;
QAction *act = wnd.menuBar()->addMenu("SomeMenu")->addMenu("someSubmenu")->addAction("someAction");
QObject::connect(act,SIGNAL(triggered()),
someObj,SLOT(actionReaction()));
I think addMenu() addAction() should work in more reliable way. This approach works for me.
I'm not sure to understand exactly what you're willing to do into your Move() slot.
But here is your own code (I removed what seemed useless to me), modified so that it is not crashing on my computer :
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QAction>
#include <QMenu>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
private:
QMenu* menu;
QAction *dummyaction;
QMenu* m_pSubMenu;
private slots:
void Move();
};
#endif // MAINWINDOW_H
mainwindow.cpp :
#include "mainwindow.h"
#include <QMenuBar>
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
m_pSubMenu = NULL;
QMenuBar* pMenuBar = new QMenuBar(this);
setMenuBar(pMenuBar);
dummyaction = new QAction("Testing",this);
menu = new QMenu("Test", this);
menu->addAction(dummyaction);
this->menuBar()->addMenu(menu);
connect(menu, SIGNAL(aboutToShow()), this, SLOT(Move()));
}
void MainWindow::Move() {
if (!m_pSubMenu) {
m_pSubMenu = new QMenu(menu);
dummyaction->setMenu(m_pSubMenu);
}
QAction* pAction = new QAction("Test", this);
m_pSubMenu->addAction(pAction);
}
I don't know exactly what you want to do into your Move() slot, but as an example, each time the Move() slot is called, a new submenu item is added.
Hope this helps.

Resources