Promoting QWidget in Qt creator, problems with constructor - c++

I subclassed QGraphicsView:
class CustomGraphicsView : public QGraphicsView
{
public:
CustomGraphicsView(QWidget *parent = 0);
...
}
The constructor in the .cpp file is then implemented like this:
CustomGraphicsView::CustomGraphicsView(QWidget * parent):
QGraphicsView(parent)
{
}
Now I promoted a QGraphicsView Widget via a Qt creator to CustomGraphicsView. But when I want to connect to the promoted widget in the constructor of my ImageWindow class;
ImageWindow::ImageWindow(QWidget *parent) :
QDialog(parent),
ui(new Ui::ImageWindow)
{
ui->setupUi(this);
CustomGraphicsView * view = ui->graphicsView();
}
I get the error message:
term does not evaluate to a function taking 0 arguments.
I specified a default value for the constructor namely QWidget *parent = 0, and in ui_image_window.h an argument is set:
graphicsView = new CustomGraphicsView(ImageWindow);
So what could cause this error then?

This is because graphicsView is a member rather than a method, so you do not need the parentheses. Just access it like view = ui->graphicsView. This is the same for all Qt widgets in your generated UI class - they are just members, not methods.

Related

Adding widget to layout only works in constructor of custom class

I have a class MainWindow subclassing QMainWindow. As the central widget I have a QScrollArea with a QWidget inside, as a container for my own custom widgets. I set a QVBoxLayout as the layout for the QWidget container and pass this layout to the constructor of my custom class, which is supposed to dynamically create instances of my custom widget class and add them to the layout.
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = Q_NULLPTR);
virtual ~MainWindow ();
private:
QVBoxLayout mainLayout;
QScrollArea scrollArea;
QWidget container;
NotificationControl control;
};
MainWindow::MainWindow (QWidget *parent) :
QMainWindow(parent),
container(&scrollArea),
control(&mainLayout) {
container.setLayout(&mainLayout);
scrollArea.setWidget(&container);
setCentralWidget(&scrollArea);
}
Now in my NotificationControl class I have a method addNotification:
void NotificationControl::addNotification (Notification notif) {
qDebug() << "NotificationControl addNotification" << notif.get_app_name();
NotificationWidget* widget = new NotificationWidget(notif);
container->addWidget(widget);
}
When this method is called, I get the debug output, but nothing is added to the layout. But if I add this to the end of the constructor of NotificationControl...
NotificationWidget* notif = new NotificationWidget(Notification());
container->addWidget(notif);
...for some reason it works. I'm pretty sure the problem isn't the NotificationWidget class. For testing purposes I made some changes, it doesn't actually use the Notification object that is passed at all.
What could be the problem?
Edit: I just noticed that adding widgets later (not in constructor) makes the widgets added in the constructor disappear.
Any widget added as a child widget must be explicitly shown if the parent widget is already visible. Usually, the child widgets are added before the parent widget is shown, and they then become visible themselves, too. But if you add them later, you must make them explicitly visible.

Qt build menu for touch screen

i want to build a QT application for windows/android.
I have one mainwindow in which i have different buttons to call submenus, as you can see on the pictures. What do you think is the best implementation for that?
I thought about replacing the central widget
Using QStackwidget
Or open a new widget on the same position and size and close after.
What do you think? Do you have some favourite implementation or do i miss some important?
Edit
My Mainwindow constructor
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
m_stacked = new QStackedWidget;
HomeScreen *homescreen=new HomeScreen(m_stacked);
Control *manual=new Control(m_stacked);
m_stacked->addWidget(homescreen);
m_stacked->addWidget(manual);
this->setCentralWidget(m_stacked);
}
Implementation of every Screen
class HomeScreen : public QWidget
{
Q_OBJECT
public:
explicit HomeScreen(QStackedWidget* stack, QWidget *parent = 0);
~HomeScreen();
private slots:
void on_pushButton_clicked();
private:
Ui::HomeScreen *ui;
QStackedWidget *m_stacks;
};
HomeScreen::HomeScreen(QStackedWidget* stack,QWidget *parent) :
m_stacks(stack),QWidget(parent),
ui(new Ui::HomeScreen)
{
ui->setupUi(this);
}
HomeScreen::~HomeScreen()
{
delete ui;
}
void HomeScreen::on_pushButton_clicked()
{
m_stacks->setCurrentIndex(1);
}
What is your solution to change the current Widget, inside a widget of the QStackwidget? I used the solution above what do you think about it?
QStackedWidget was made right for that, I don't see any reason why you should incline to other options. You can always removeWidget(widget) and delete widget; if you want to free the memory of some rarely used menu.
Edit:
Your code is fine, there can be only a few enhancements made. You can create enum for your indexes in some separate header file.
Option 1:
If you use only QStackedWidget as a parent menu, you can adjust the constructor:
HomeScreen(QStackedWidget* parent) :
QWidget(parent),
ui(new Ui::HomeScreen)
{
ui->setupUi(this);
}
If you'd want to access QStackedWidget and change an index, you spare m_stacks pointer and use the parent: dynamic_cast<QStackedWidget*>(parent())->setCurrentIndex(1 /* or enum */);.
Option 2:
Leave index changing to the parent MainWindow. Each menu will have a request signal:
signals:
void goToMenuRequest(int index /* or enum */);
which you connect to m_stacked's setCurrentIndex in the constructor of MainWindow.
Not a big things, but It'll make coding easier.

How to add a Menubar to a QWidget?

I am currently writing a C++ Application using the Qt framework, in which the 'main window' inherits from the QWidget class:
class Draughts : public QWidget
{
Q_OBJECT
public:
explicit Draughts(QWidget *parent = 0);
~Draughts();
private:
Ui::Draughts *ui;
};
And I attempted to add a simple menu bar to the application, using the following code:
Draughts::Draughts(QWidget *parent) :
QWidget(parent),
ui(new Ui::Draughts)
{
ui->setupUi(this);
QWidget *menuWidget = new QWidget;
QMenu *menuGame = new QMenu("Game");
menuGame->addAction("New");
menuGame->addAction("Exit");
QMenu *menuHelp = new QMenu("Help");
menuHelp->addAction("How to Play...");
menuHelp->addAction("About");
//Setup the Application Menu
QMenuBar mainMenu(this);
mainMenu.addMenu(menuGame);
mainMenu.addMenu(menuHelp);
}
Should I be using the QMainWindow class instead of the QWidget class for my application?
It would be easier to use QMainWindow, because it provides a convenient menuBar() method:
QMenuBar* mainMenu = this->menuBar();
But it is possible to add it to QWidget, just as any other widget. Just don't allocate it in the local scope, because it will be deleted after the function finishes. Instead, do it like with other widgets:
QMenuBar mainMenu = new QMenuBar(this);
You should also probably add a layout to your widget, and add the menu to the layout to have more control over where does it appear. You may find this tutorial useful.

Browser of file

I'm trying to develop a file browser in Qt and C++.
Opening a FileSystem can take a lot of memory. In that way, the best is to only open what is inside a folder when I click on it.
In my browser.h, I have declared the OnClick signal.
class Browser : public QTreeWidget
{
Q_OBJECT
public:
Browser(USBDevice dev, QWidget* parent = 0);
QTreeWidget(parent)
{
connect(this , SIGNAL(itemClicked(QTreeWidgetItem*,int)),this,
// SLOT(showDirectory(QTreeWidgetItem*,int)));
};
~Browser(){};
public slots:
void showDirectory(QTreeWidgetItem* item, int /*column*/)
{
...
}
};
QTreeWidget is failing to build saying :
error: function definition does not declare parameters - QTreeWidget(parent)
in the browser.cpp, I have wrote the code to create window, widget..
Browser::Browser(USBDevice dev, QWidget *parent) :
QTreeWidget(parent)
{
QMainWindow *window = new QMainWindow();
window->setWindowTitle(QString::fromUtf8("PULS"));
window->resize(400, 400);
QWidget *centralWidget = new QWidget(window);
QTreeWidget *MyTree = new QTreeWidget(centralWidget);
MyTree->setFixedSize(395,395);
}
//Set QTreeWidget Column Header
QTreeWidgetItem* headerItem = new QTreeWidgetItem();
headerItem->setText(0,QString("File Name"));
headerItem->setText(1,QString("Size (Bytes)"));
headerItem->setText(2,QString("Date"));
MyTree->setHeaderItem(headerItem);
I don't understand but How to manage connect ?
You've got a ; instead of a : before the initialiser list for your constructor:
Browser(USBDevice dev, QWidget* parent = 0); // <--- here
QTreeWidget(parent)
{
...
FWIW, I recommend putting the colon at the start of the line like this:
Browser(USBDevice dev, QWidget* parent = 0)
: QTreeWidget(parent)
{
...
That way it's much clearer how the second line relates to the first and third, and you'll get in the habit of editing the declaration when you go to make it a definition, avoiding the kind of problem you had.

Accessing a widget from outside of its class?

In Qt Creator, I have a couple of widgets declared like so:
Header File:
class MapViewer : public QGraphicsView
{
Q_OBJECT
public:
explicit MapViewer(QGraphicsScene *scene, QWidget *parent = 0);
~MapViewer();
public slots:
void mousePressEvent(QMouseEvent *event);
};
// Declaration for the map editor window.
class MapEditor : public QMainWindow
{
Q_OBJECT
public:
explicit MapEditor(QWidget *parent = 0);
~MapEditor();
public:
QLayout *editorLayout;
QPushButton *btn;
QGraphicsScene *mapScene;
MapViewer *mapView;
private:
Ui::MapEditor *ui;
};
CPP File:
MapEditor::MapEditor(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MapEditor)
{
ui->setupUi(this);
this->setWindowTitle("2DXY :: Map Editor");
this->setGeometry(10,10,1170,750);
editorLayout = new QVBoxLayout; // Create a new layout
this->setLayout(editorLayout); // Set the widget's layout to our newly created layout.
mapScene = new QGraphicsScene(); // Create a new graphics scene to draw upon.
mapView = new MapViewer(mapScene,this); // Create a new graphics view to display our scene - set its parent to 'this' so that it doesn't open in a new window.
mapView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
mapView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
mapView->setGeometry(20,20,1178,546); // Width first, then height.
AND:
void MapViewer::mousePressEvent(QMouseEvent *event)
{
// Show an empty message box, just to check that the event handler works!
QMessageBox *notification = new QMessageBox();
notification->show();
notification->exec();
// Some how access the same QGraphicsScene and View (mapScene, mapView) as above, so
// I can update their contents on the open form / window.
}
And as you can see, I wish to access the Graphics Scene again to update it, then redraw it (or whatever). But I'm not able to access the graphics scene at all, despite a few hours of trial and error with declaring widgets in different ways.
I know that the listener itself works, because if it's set to open a new message box, or output to the debug window, then it works, it's just that I can't access the widgets I've already defined.
I feel that there is a (relatively) easy solution to this problem, and that I'm just missing something obvious.
You passed the QGraphicsScene to your MapRender object's constructor. What do you do with the scene within its constructor? Ideally, you should be storing it as a data member of MapRender. For example:
class MapRender {
public:
MapRender(QGraphicsScene* scene)
: scene_(scene)
{
}
public slots:
void mousePressEvent(QMouseEvent *event);
private:
QGraphicsScene* scene_;
}
Now in your implementation of mousePressEvent, you can access to the scene member:
void MapRender::mousePressEvent(QMouseEvent *event) {
int CursorX = event->globalX();
int CursorY = event->globalY();
QGraphicsRectItem *clickedBox = new QGraphicsRectItem(40,40,32,32);
clickedBox->setBrush(QBrush(Qt::blue));
scene_->addItem(clickedBox);
}
Keep in mind you should ideally be putting the implementation of the constructor in your cpp file, but my example does it in the declaration for brevity.
void MapViewer::mousePressEvent(QMouseEvent *event)
{
// Show an empty message box, just to check that the event handler works!
QMessageBox *notification = new QMessageBox();
notification->show();
notification->exec();
// To add something whenever the user clicks, you don't need the view,
// just the scene.
scene()->addItem( new MyItem() );
}
Remember MapViewer derives from QGraphicsView and the view must know about the scene it belongs to - so it has a scene() method to return it, which you inherited.