I have a simple widget which uses an image as background and contains some child widgets. When I create it without a parent (as a dialogue) everything is perfect. But if I create it as a child of some other widget, I can't see the background.
Can I use QWidget::setPalette to set the background for a child widget?
If not, how would you accomplish this?
#include <QWidget>
#include <QPixmap>
#include <QPalette>
#include <QLabel>
class Panel : public QWidget
{
Q_OBJECT
public:
explicit Panel(QWidget *parent = 0) QWidget(parent)
{
bgnd_ = new QPixmap(":/path/to/image.png");
PaintBackground();
QLabel* lbl = new QLabel("SomeChild",this);
}
private:
void PaintBackground()
{
QPixmap bgnd = bgnd_->scaled(this->size(), Qt::IgnoreAspectRatio);
QPalette palette;
palette.setBrush(QPalette::Background, bgnd);
this->setPalette(palette);
}
protected:
void resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
PaintBackground();
}
private:
QPixmap* bgnd_;
};
If I create this widget as an independent object with no parent, then it will render fine. I see the background and the child widget. If I create this widget as a child of another widget, then I see the lowest-level child, but the background is empty.
#include <QMainWindow>
#include "panel.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0) :
QMainWindow(parent)
{
Panel* solo = new Panel();
solo->show();
Panel* child = new Panel(this);
}
};
The above class instantiates the widget in 2 ways: solo gives me a dialogue with everything looking perfect. child lets me see Panel's child widgets, but the background is white.
Troubleshooting details
I thought this could be a bug in Qt as described here so I tried filtering out ThemeChange events by reimplementing the following in both Panel and MainWindow.
bool event(QEvent *event) override
{
if (event->type() != QEvent::ThemeChange)
{
return QWidget::event(event);
}
return true;
}
That didn't help.
Instead of painting my background with a QPalette in resizeEvent I found that the answer was to paint it with QPainter in paintEvent.
#include <QWidget>
#include <QPixmap>
#include <QPainter>
#include <QLabel>
class Panel : public QWidget
{
Q_OBJECT
public:
explicit Panel(QWidget *parent = 0) : QWidget(parent)
{
bgnd_ = new QPixmap(":/path/to/image.png");
QLabel* lbl = new QLabel("Hello",this);
}
protected:
void paintEvent( QPaintEvent* e )
{
QPainter painter( this );
painter.drawPixmap( 0, 0, bgnd_->scaled(size(), Qt::IgnoreAspectRatio));
QWidget::paintEvent( e );
}
private:
QPixmap* bgnd_;
};
Related
I want to install an event filter on an object of a custom class in Qt. So I created a project such as QtGuiApplication1 on the Qt Designer and created a simple class as myClass as which has a widget and a QGraphicsView for drawing a colored rectangle.
in header file:
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_QtGuiApplication1.h"
#include "myClass.h"
class QtGuiApplication1 : public QMainWindow
{
Q_OBJECT
public:
QtGuiApplication1(QWidget *parent = Q_NULLPTR);
private:
Ui::QtGuiApplication1Class ui;
bool eventFilter(QObject *obj, QEvent *ev);
myClass* myClass_;
};
in .cpp
#include "QtGuiApplication1.h"
QtGuiApplication1::QtGuiApplication1(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
myClass_ = new myClass(this, QRect(100, 100, 200, 200));
myClass_->installEventFilter(this);
}
bool QtGuiApplication1::eventFilter(QObject * obj, QEvent * ev)
{
if (obj == myClass_)
{
bool hi = true;
}
return false;
}
and the myClass code is here:
header file of myClass:
#ifndef MYCLASS_H
#define MYCLASS_H
#include <QObject>
#include <QGraphicsView>
class myClass : public QObject
{
Q_OBJECT
public:
explicit myClass(QObject *parent = 0);
myClass();
myClass(QWidget* parent, QRect inRect);
private:
QWidget * widget;
QGraphicsView* qGraph_back;
QGraphicsScene* scene_back;
};
#endif /
cpp file of myClass:
#include "myClass.h"
myClass::myClass(QObject *parent) :
QObject(parent)
{
}
myClass::myClass()
{
}
myClass::myClass(QWidget* parent, QRect inRect)
{
widget = new QWidget(parent);
qGraph_back = new QGraphicsView(widget);
scene_back = new QGraphicsScene(qGraph_back);
widget->setGeometry(inRect);
scene_back->setSceneRect(0,0,inRect.width(),inRect.height());
qGraph_back->setBackgroundBrush(QColor(0, 0, 255, 80));
qGraph_back->setScene(scene_back);
qGraph_back->show();
}
I want to get all the events of myClass_ object such as mouse event, But I can't and the eventfilter doesn't work. how to install eventfilter on the object?
The event filter will work only for events in your MyClass instance, only. Not for its children.
So, events, such as a mouse click or move, in your qGraph_back will be not visible in your eventFilter method.
When you add a child in a widget, an QChildEvent event is raised. You can use it to install the event filter on all children (and grandchildren, etc.). But, you have to install the event filter on your MyClass before adding the children.
A quick example:
class Listener: public QObject
{
public:
Listener(): QObject()
{}
bool eventFilter(QObject* object, QEvent* event)
{
qDebug() << Q_FUNC_INFO << object << event;
if (event->type() == QEvent::ChildAdded)
{
QChildEvent* ev = dynamic_cast<QChildEvent*>(event);
ev->child()->installEventFilter(this);
}
return false;
}
};
class Widget: public QWidget
{
public:
Widget(QObject* parent) : QWidget()
{
installEventFilter(parent);
QGraphicsView* view = new QGraphicsView(this);
auto layout = new QHBoxLayout(this);
layout->addWidget(view);
layout->addWidget(new QLabel("Foobar"))
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Listener* listener = new Listener();
Widget* w = new Widget(listener);
w->show();
return app.exec();
}
As you can see, the events in the QLabel are now sent to the listener. But, you can't see the events from the view because they are caught by the viewport widget in the QGraphicsView...
You have to handle the case where the added child has a viewport (inherits from QAbstractItemView, etc.) and it becomes more complicated.
So, if you have to know when the user clicks on your view, it would be easier to use signals/slots and not an event filter.
I wrote a minimal working example of the problem and I believe it might be a Qt bug. But just in case I wanted to ask.
Here are My classes:
mydialog.h
#include <QDialog>
#include <QVBoxLayout>
#include <QLabel>
class MyDialog : public QDialog
{
public:
MyDialog(QWidget *parent = 0);
};
mydialog.cpp
#include "mydialog.h"
MyDialog::MyDialog(QWidget *parent):QDialog(parent)
{
QLabel *label = new QLabel("Some random dialog",this);
QVBoxLayout *layout = new QVBoxLayout();
layout->addWidget(label);
this->setLayout(layout);
}
myitem.h
#include <QGraphicsTextItem>
#include <QPainter>
#include <QDebug>
#include "mydialog.h"
class MyItem : public QGraphicsItem
{
public:
MyItem();
void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0);
QRectF boundingRect() const {return boundingBox;}
void setMyDialog(MyDialog *d){ dialog = d; }
private:
QRectF boundingBox;
MyDialog *dialog;
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *e);
};
myitem.cpp
MyItem::MyItem()
{
boundingBox = QRectF(0,0,200,100);
}
void MyItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){
painter->setBrush(QBrush(Qt::red));
painter->drawRect(boundingBox);
}
void MyItem::mousePressEvent(QGraphicsSceneMouseEvent *e){
//dialog->exec(); // BUG
//dialog->open(); // BUG
dialog->show(); // WORKS!
}
test.h
#include "myitem.h"
namespace Ui {
class Test;
}
class Test : public QMainWindow
{
Q_OBJECT
public:
explicit Test(QWidget *parent = 0);
~Test();
protected:
void resizeEvent(QResizeEvent *e);
private:
Ui::Test *ui;
MyDialog *diag;
};
And test.cpp
Test::Test(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Test)
{
ui->setupUi(this);
ui->graphicsView->setScene(new QGraphicsScene(this));
diag = new MyDialog(this);
}
void Test::resizeEvent(QResizeEvent *e){
ui->graphicsView->setSceneRect(0,0,ui->graphicsView->width(),ui->graphicsView->height());
ui->graphicsView->scene()->clear();
MyItem *item = new MyItem();
item->setMyDialog(diag);
ui->graphicsView->scene()->addItem(item);
}
Test::~Test()
{
delete ui;
}
So here is what happens (tested on Qt 5.7 and Qt 5.6). If the dialog is opened with either exec or open then, after it is closed ALL further mouse clicks ANYWHERE on the screen will open up the dialog again, making it impossible to interact with anything else drawn in there. This happens ONLY after it is opened for the first time. If i resize the screen, the item is recreated and I can click normally again. If I again click on the red box, then again all further clicks anywhere on the screen open up the dialog
However if the Dialog is opened by show, then it works as expected, only showing again if I click on the red rectangle.
Now the obvious problem is that exec make the dialog block execution until it is closed, but show doesn't. I can program around this using signals, but my question is why? and Is this a bug?
It seems that MyItem's reimplementation of mousePressEvent needs some behavior provided by default implementation. Here is the code, works fine in my machine:
void MyItem::mousePressEvent(QGraphicsSceneMouseEvent *event){
dialog->exec(); // WORKS
//dialog->open(); // WORKS
//dialog->show(); // WORKS
QGraphicsItem::mousePressEvent(event);
}
I am having problems with QImages and Qthreads.
I am trying to load big images in a Thread and then display them as QPixmap on a QLabel.
My problem is that as long as I don't use a different thread to load the QImages, everything is perfect but as soon as I use a different thread, nothing is renderder.
Though I still have a valid size for my QImage.
The thing that puzzles me is that, if I just comment the 22nd line in the cpp that moves the loader to the other thread, the label displays nicely.
Does anyone have an idea?
Here is my very simplified code:
Header :
class Loader : public QObject
{
Q_OBJECT
public:
explicit Loader(QObject *parent = 0);
signals:
void imageLoaded(QString, const QImage &);
public slots:
void loadImage(const QString& fichier);
};
namespace Ui {
class MainWindow;
}
class LoaderImages;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
signals:
void loadImage(const QString& dossier);
private slots:
void imageAvailable(const QString& dossier, const QImage& img);
private:
Ui::MainWindow *ui;
//QString mDossier;
Loader* mLoader;
//QMap<QString, QImage*> mMapDesImages;
int mWidth;
};
cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFile>
#include <QPixmap>
#include <QImage>
#include <QDir>
#include <QThread>
#include <QDebug>
#include <QLabel>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
mLoader(new Loader(NULL)),
mWidth(0)
{
ui->setupUi(this);
QThread* thread = new QThread(this);
mLoader->moveToThread(thread);
thread->start();
connect(this, SIGNAL(loadImage(QString)), mLoader, SLOT(loadImage(QString)));
connect(mLoader, SIGNAL(imageLoaded(QString,QImage)), this, SLOT(imageAvailable(QString,QImage)));
emit loadImage("C:/img.jpg");
}
void MainWindow::imageAvailable(const QString &dossier, const QImage& img)
{
mWidth += (img.width() + 20);
ui->mScrollContent->setMinimumSize(mWidth,img.height());
QLabel* lab = new QLabel(ui->mScrollContent);
lab->setFixedSize(img.width(), img.height());
lab->setGeometry(mWidth - img.width() + 20, 0, img.width(), img.height());
lab->setPixmap(QPixmap::fromImage(img));
}
MainWindow::~MainWindow()
{
delete mLoader;
delete ui;
}
Loader::Loader(QObject *parent) :
QObject(parent)
{
}
void Loader::loadImage(const QString& fichier)
{
QImage* image = new QImage(fichier);
emit imageLoaded(fichier, *image);
}
Thx!
There are several mistakes:
You're not showing the label. When the image loader is in the GUI thread, the image is loaded and the label added to the contents pane before the main window is shown. Since the parent is shown, the children become visible.
When the loading is done in another thread, you'll be adding image labels to a widget that's already shown. Such child widgets are not visible unless you explicitly show() them.
You're leaking the image in loadImage. There's no reason to put that QImage on the heap.
You're allowing a running QThread to be destructed. That's a common error since QThread is essentially broken by design. Sane C++ classes should be always destructible. QThread isn't. Thus you need a workaround.
You're not setting the minimum height of the contents widget as well.
You might wish to consider the use QtConcurrent::run instead of a dedicated thread. This is especially worthwhile when the operation you're undertaking is a one liner, more or less. I've shown both, the implementations are alternated between at runtime. Note that you need to add the concurrent module and CONFIG += c++11 to the project file.
Style bugs:
There's no reason to pass NULL for default-valued parameters that are already zero.
There's no reason to keep QObject members that have the lifetime of the parent object on the heap, if such members are constructed along with the parent object.
Just because Qt Creator comes with silly template files doesn't mean that you shouldn't be using a std::unique_ptr or QScopedPointer to hold the ui member. Naked pointers should almost never be members unless they're pointers to QObjects with parents.
As quite a bit of the code is missing, I can't really tell what else might be wrong. Below is a complete example.
// https://github.com/KubaO/stackoverflown/tree/master/questions/image-loader-24853687
#include <QtWidgets>
#include <QtConcurrent>
class Thread final : public QThread {
public:
~Thread() { quit(); wait(); }
};
class Loader : public QObject
{
Q_OBJECT
public:
explicit Loader(QObject *parent = nullptr) : QObject(parent) {}
Q_SIGNAL void imageLoaded(const QString &, const QImage &);
Q_SLOT void loadImage(const QString& fichier) {
QImage img(fichier);
if (! img.isNull()) emit imageLoaded(fichier, img);
}
};
class MainWindow : public QWidget
{
Q_OBJECT
Loader m_loader;
Thread m_loaderThread;
QGridLayout m_layout{this};
QPushButton m_open{"Open"};
QScrollArea m_view;
QWidget m_content;
int m_width{};
bool m_threadImpl = true;
Q_SIGNAL void loadImage(const QString &);
Q_SIGNAL void imageLoaded(const QString &, const QImage & img);
Q_SLOT void imageAvailable(const QString &, const QImage & img) {
int spacing = 20;
if (m_width) m_width += spacing;
auto lab = new QLabel(&m_content);
lab->setFixedSize(img.width(), img.height());
lab->setGeometry(m_width, 0, img.width(), img.height());
lab->setPixmap(QPixmap::fromImage(img));
lab->show();
m_width += img.width();
m_content.setMinimumWidth(m_width);
m_content.setMinimumHeight(qMax(m_content.minimumHeight(), img.height()));
}
Q_SLOT void open() {
auto dialog = new QFileDialog(this);
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->show();
if (m_threadImpl)
connect(dialog, &QFileDialog::fileSelected, this, &MainWindow::loadImage);
else
connect(dialog, &QFileDialog::fileSelected, [this](const QString & fichier){
QtConcurrent::run([this, fichier]{
QImage img(fichier);
if (! img.isNull()) emit this->imageLoaded(fichier, img);
});
});
m_threadImpl = !m_threadImpl;
}
public:
explicit MainWindow(QWidget *parent = nullptr) : QWidget(parent) {
m_layout.addWidget(&m_open);
m_layout.addWidget(&m_view);
m_view.setWidget(&m_content);
m_loader.moveToThread(&m_loaderThread);
m_loaderThread.start();
connect(&m_open, &QPushButton::clicked, this, &MainWindow::open);
connect(this, &MainWindow::loadImage, &m_loader, &Loader::loadImage);
connect(this, &MainWindow::imageLoaded, this, &MainWindow::imageAvailable);
connect(&m_loader, &Loader::imageLoaded, this, &MainWindow::imageAvailable);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
#include "main.moc"
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
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.