I am trying to adapt the opengl Es example "Hello GL" featured here - http://qt-project.org/doc/qt-4.8/opengl-hellogl-es.html. I am basically looking for a simple way to get a 3D graphics rendering window into a form made in Qt creator.
The first thing I tried:
Grid layout is a layout I created in Qt Creator.
#include <QProcess>
#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>
#include <QTimer>
#include "glwidget.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
GLWidget *glwidget = new GLWidget(); // This is mandatory. No problems here.
QTimer *timer = new QTimer(this); // Need this for the example to work.
timer->setInterval(10); // Also necessary.
ui->gridLayout->addWidget(glwidget);
Which compiles, but then promptly crashes with a segmentation fault.
ui->gridLayout->addWidget(new GLWidget);
Segfaults the same way.
The debugger points me toward line 104 of qgridlayout.h:
inline void addWidget(QWidget *w) { QLayout::addWidget(w); }
Not sure what to make of that. Perhaps the QGLWidget wants to do something before I call ui->setupUi(this)? Perhaps it can't add the widget to the layout for some reason?
Of course if I comment out the line where I am added the widget, the program works flawlessly.
Any ideas for what's going on here?
Edit: I have fixed this. It was problem with order of operations - I called updateui too quickly.
The setupUi function in the generated form class initializes all variables of the form class, so using the variables before the form is initialized is undefined behaviour, since the variables contain garbage.
So the solution is to call:
ui->setupUi(this)
Before any call that uses variables in the ui object.
I'm not sure, but I think the problem is with the following line:
ui->gridLayout->addWidget(GLWidget);
I think, you should write it as follows:
ui->gridLayout->addWidget(glwidget);
// declare glwidget as member of your class
GLWidget *glwidget;
//in constructor use
glwidget = new GLWidget();
Related
I'm learning QT (I already know C++ very well) and trying to get a UI to display well but I do not want to use the QT Designer that comes with QT Creator. I have the following class:
#include "MainPanel.h"
#include<QVBoxLayout>
MainPanel::MainPanel(QWidget *parent)
: QWidget(parent)
{
QLayout *lo = new QVBoxLayout(this);
mList = new QListWidget(this);
mList->addItem("Testing");
setLayout(lo);
lo->addWidget(mList);
lo->setSpacing(5);
}
The Main window class has a bunch of extra protected functions but the initControls method just does this:
void MainWindow::initControls()
{
QHBoxLayout *loMain = new QHBoxLayout(this);
loMain->addWidget(new MainPanel(this));
setLayout(loMain);
}
When I put all the code from MainPanel into MainWindow::initControls() or even in the constructor(either way), it works - shows a list widget with a single item "Testing". With the code in MainPanel though, it shows up as a very small rectangle that wouldn't fit the word "Testing" nor is there any semblance of text in there even partially.
I have tried to override sizeHint() in and move the code to create and return the list widget to a method getList() so I can access it from sizeHint too but that did nothing - I still get a small rectangle.
What am I doing wrong and what do I need to do or include to get the widget to paint properly? I have more controls I want to add to this UI (a button panel below the list widget and a detail panel on the right 2/3 of the window) but until I can get this to display, I can't possibly proceed with the rest.
I also want to do this entirely with code - not using the designer as I have vision issues and found it to be difficult to place things correctly on the form.
Someone please help - documentation and tutorials other than the documentation on QT's website is helpful if it points me to the right direction. I have already looked on QT's docs site under QWidget, QListWidget, QLayout, and QH(and V)BoxLayouts but see nothing and many of the tutorials talk about the designer.
Before someone tries to scold about creating a SSME or whatever small program - I have given you the smallest one that displays the issue - I know that putting the code all into the main window fixes it but one should never have everything in one class.
Okay, too unclear, what's happening there, we should have requested for more of your code =)
Here is the smallest possible sample, demonstrating what you should have been trying to achieve:
mainwindow.cpp:
#include "mainwindow.h"
#include "mainpanel.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
MainPanel* p = new MainPanel(this);
setCentralWidget(p);
}
mainpanel.h:
#include "mainpanel.h"
#include <QListWidget>
#include <QLayout>
MainPanel::MainPanel(QWidget *parent)
: QWidget(parent)
{
QLayout *lo = new QVBoxLayout(this);
QListWidget* mList = new QListWidget(this);
mList->addItem("Testing");
setLayout(lo);
lo->addWidget(mList);
lo->setSpacing(5);
}
main.cpp:
#include <QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow w;
w.resize(400, 500);
w.show();
return app.exec();
}
Seemingly, you've tried to set a layout on QMainWindow, but it already has a built-in layout, it is exactly the case when setCentralWidget should work, leave manual layout creation for QWidget & QDialog subclasses.
The code above works fine, try it and refactor the way you want.
#MasterAler is correct that the root cause of your issue is setting a layout MainWindow. The reason for using a MainWindow is to support standard VBoxLayout of menubar, central widget, and status bar. So it makes no sense to set your own layout for a QMainWindow.
Since we didn't have your entire code, I didn't assume MainWindow was a QMainWindow. I got your code to work by making MainWindow a QDialog. This may be more of what you were originally looking for, where you want to put a widget of your own making into any container. Following is in Python (I find Python a faster prototyping environment than C++), but you can easily read it and see how to host your MainPanel is any widget (not just a MainWindow):
import sys
from PySide2.QtWidgets import QApplication, QWidget, QListWidget, QDialog, QVBoxLayout, QHBoxLayout
class MainPanel(QWidget):
def __init__(self, parent):
QWidget.__init__(self, parent)
lo = QVBoxLayout(self)
lo.setSpacing(5)
self.setLayout(lo)
mList = QListWidget(self)
mList.addItem("Testing")
lo.addWidget(mList)
class MainWindow(QDialog):
def __init__(self, parent):
QDialog.__init__(self, parent)
loMain = QHBoxLayout(self)
loMain.addWidget(MainPanel(self))
self.setLayout(loMain)
if __name__ == "__main__":
app = QApplication(sys.argv)
# Show the form
window = MainWindow(None)
window.exec_()
I have been working on a simple notepad application using QT, and am currently stuck at a place where I have to disable the actionUndo and actionRedo when undo or redo are not applicable respectively. I used the connect method of QT, and currently my constructor function (along with includes) looks like this:
#include "notepad.h"
#include "ui_notepad.h"
#include "about.h"
#include <QFile>
#include <QTextStream>
#include <QFileDialog>
#include <QIcon>
#include <QFont>
#include <QFontDialog>
#include <QTextCursor>
Notepad::Notepad(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Notepad)
{
ui->setupUi(this);
setWindowTitle("QNotepad");
setWindowIcon(QIcon(":/icons/icons/qnotepad.png"));
setCentralWidget(ui->textBody);
//Enabling the options, only when applicable
connect(ui->textBody, SIGNAL(undoAvailable(bool)), ui->actionUndo, SLOT(setEnabled(bool)));
connect(ui->textBody, SIGNAL(redoAvailable(bool)), ui->actionRedo, SLOT(setEnabled(bool)));
}
Full sources are here
But seems it is not working as when I run the program, the actionUndo and actionRedo remains enabled even when there is no undo and redo operations available.
I am using Arch Linux as the primary development environment
Qt Ui elements (widgets, actions, etc.) are enabled by default, so you need to uncheck the enabled flag for the Undo and Redo action in the property window of Qt designer for your notepad.ui file.
Alternatively you could do it in the constructor of your window like this:
ui->actionUndo->setEnabled(false);
ui->actionRedo->setEnabled(false);
//Enabling the options, only when applicable
connect(ui->textBody, &QTextEdit::undoAvailable, ui->actionUndo, &QAction::setEnabled);
connect(ui->textBody, &QTextEdit::undoAvailable, ui->actionRedo, &QAction::setEnabled);
In this way they will be on/off only when the QTextEdit emits the signal.
Also consider to use the functor syntax for your signal/slot connection, as shown in my code snipped, because it has several advantages. See here to learn more.
I want to show a file system using QTreeView on a QDockWidget. The tree will be dynamically changed, so I decided to use QTreeView instead of QTreeWidget.
Here is my code:
QFile file(":/default.txt");
file.open(QIODevice::ReadOnly);
TreeModel model(file.readAll());
file.close();
QTreeView w;
w.setModel(&model);
swatch1->setWidget(&w);
w.setEnabled(true);
addDockWidget(leftarea, swatch1);
swatch1 is of type QDockWidget. The above code is inside a function body of type (inherited from) MainWindow. The code runs smoothly, and the tree does not show up.
I also tried another way: putting QTreeView into a QVBoxLayout (using setWidget method), which in turn be put into a QDockWidget (using setLayout method). This 2nd code also runs smoothly, and the tree does not show up.
This code is copied from a working example on Qt Creator IDE, and I tested it working. The only difference is, in the original QTreeView example, the above code is placed inside the main() { ..... } function.
Does anyone has a working example, putting QTreeView into QDockWidget and working (the code actually shows the tree)? Thanks in advance.
I'm not quite sure what went wrong in the OP. However, I made a minimal complete sample to see whether there are pitfalls:
// standard C++ header:
#include <iostream>
#include <string>
// Qt header:
#include <QApplication>
#include <QDockWidget>
#include <QFileSystemModel>
#include <QMainWindow>
#include <QTreeView>
using namespace std;
int main(int argc, char **argv)
{
cout << QT_VERSION_STR << endl;
// main application
#undef qApp // undef macro qApp out of the way
QApplication qApp(argc, argv);
// setup GUI
QMainWindow qWin;
QDockWidget qDock;
qDock.setAllowedAreas(Qt::AllDockWidgetAreas);
QTreeView qTreeView;
QFileSystemModel qFSModel;
qTreeView.setModel(&qFSModel);
QString path = QDir::currentPath();
QModelIndex indexPath = qFSModel.index(path);
qTreeView.scrollTo(indexPath);
qDock.setWidget(&qTreeView);
qWin.addDockWidget(Qt::TopDockWidgetArea, &qDock);
qWin.show();
// run application
return qApp.exec();
}
Compiled and tested it with VS2013, Qt 5.6 on Windows 10 (64 bit):
As can be seen in the snapshot, the QTreeView is visible (docked and undocked). I checked that both re-act on mouse clicks - they did.
(I guess this is one of my most minimal Qt applications I ever wrote.)
Scheff,
Thank you very much for your answer. Sorry I may not be clear about what I am asking: the tree become visible when this code section is in the main() { ....} function:
QFile file(":/default.txt");
file.open(QIODevice::ReadOnly);
TreeModel model(file.readAll());
file.close();
QTreeView w;
w.setModel(&model);
w.show();
But the same code (almost same) does not working (program runs but the tree is not visible) when this section of code is in a class function inside MainWindow and QTreeView is added to a QDockWidget:
QFile file(":/default.txt");
file.open(QIODevice::ReadOnly);
TreeModel model(file.readAll());
file.close();
QTreeView w;
w.setModel(&model);
swatch1->setWidget(&w);
addDockWidget(leftarea, swatch1);
here, leftarea is a Qt:DockWidgetArea, and swatch1 is an object of type inherited from QDockWidget. when run this program, swatch (a QDockWidget) is visible, but not the tree. still struggling ...
The problem solved. The original code I wrote by itself is correct, but it is in an object method, and as soon as the execution leaves the object, the tree is destroyed.
So, it is a C++ variable scoping problem, not exactly a Qt problem. I have been using python for a while, and just switch back to C++.
Scheff, thank you for your posting confirmed to me that the Qt code is correct, and suggests to me that something else is wrong.
I have managed to get the QSystemTrayIcon visible similar to this:
using the following line of code (with the signal slots working):
#include "dialog.h"
#include "ui_dialog.h"
#include <QMessageBox>
#include <form.h>
Dialog::Dialog(QWidget *parent)
: QDialog(parent), ui(new Ui::Dialog)
{
ui->setupUi(this);
QIcon icon("/Users/JohnnyAppleseed/IMAGE.png");
m_ptrTrayIcon = new QSystemTrayIcon(icon );
m_ptrTrayIcon->setToolTip( tr( "Bubble Message" ) );
// m_ptrTrayIcon->setContextMenu(m_trayIconMenu);
connect(m_ptrTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
}
Dialog::~Dialog()
{
delete ui;
}
However, when I try to implement code to show the QWidget/QWindow near the QSystemTrayIcon that I have created, it fails to show up near it. It also shows up and disappears quickly as well (even if I didn't want it near the QSystemTrayIcon) using this code:
void Dialog::iconActivated(QSystemTrayIcon::ActivationReason reason)
{
form fr;
fr.setWindowFlags(Qt::Popup);
fr.show();
}
For the sake of being clear, I would like to show my QWidget/QWindow just like VMWare Fusion's approach (or the clock that is found on Microsoft Windows Vista or later...)
Mac OS X / Linux
Microsoft Windows
Can some one please point out what am I doing wrong? Thanks!
To make things much simpler, download the project: http://zipshare.net/sv
UPDATE #1
Regarding the QWidget/QWindow flicking issue, vahancho advised me to move the form fr; from the void Dialog::iconActivated(QSystemTrayIcon::ActivationReason reason) function to the header of the working window. And it worked successfully all thanks to vahancho. The window now shows up, but its not near the QSystemTrayIcon yet :(
The problem is that you create you form object in the stack and it gets deleted as soon as the execution goes out of you iconActivated() slot. That is why it disappears as soon as you see it. To solve the problem you need to create your pop up in the heap.
UPDATE
In order to place you dialog near the tray icon you have to determine the tray icon position. To do that you can use QSystemTrayIcon::geometry() function. You code will look like (adjust the coordinates according to your needs):
QRect rect = m_ptrTrayIcon->geometry();
fr.move(rect.x(), rect.y());
fr.show();
I've just designed my ui in the QT-Creator and, as the main application is based on two panels, I decided to use the StackedWidget for "change the layout" without opening a new window.
So, I added a QTStackedWidget named: stackedWidget (as default).
The problem is in mainwindow.cpp, I added a custom SLOT that contain:
ui->stackedWidget->setCurrentIndex(1);
when I build this the compiler says:
mainwindow.cpp:25: error: no member named 'stackedWidget' in 'Ui::MainWindow'
ui->stackedWidget->setCurrentIndex(1);
~~ ^
also in the qt-creator itself I was unable to attach a signal to the stackedWidget because it doesn't show to me the setCurrentIndex SLOT...
any advice?
Please note that I'm a noob with C++ I just used Qt a couple of years ago with PyQt4.
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
private slots:
void showOtherPage();
void showMainPage();
};
#endif // MAINWINDOW_H
mainiwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTimer>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
qDebug() << "MainWindow - Debug Mode ON";
connect(ui->btnOther, SIGNAL(clicked()), SLOT(showOtherPage()));
}
void MainWindow::showOtherPage()
{
qDebug() << "Showing Other Page";
ui->stackedWidget->setCurrentIndex(1);
}
void MainWindow::showMainPage()
{
qDebug() << "Showing Main Page";
ui->stackedWidget->setCurrentIndex(0);
}
MainWindow::~MainWindow()
{
delete ui;
}
I had a very similar issue.
One of the UI actions was defined as the others and used.
I had a ui has no member named xyz compilation error for this one only, without possible explanation.
I could solve it by unchecking/checking the Shadow build option in the project compilation options!
Hope it saves someone the 30 minutes I just lost :)
Faced the very same issue today. Recreating the project does work, though I've found a solution that won't make one rewrite everything :) Run it in Debug. Once you've done it, problem's solved.
Creating a new project fixed it... I don't know why, I'm still looking for an explanation.
I started a new project, created the stackedWidget, and tested the code for the page-switching... it just simply works... and I still do not know WHY the other one fail to build...
Checked again and again names and everything.
I tried cleaning project and running qmake without any luck. I then drilled down into the project folder and deleted the ui_***.h file and everything started working. Might have had to do with the fact Visual Studio generated that file and I was working on another computer with Qt Creator for the same project.