Basic Qt layout: Adding to a frame - qt

I am just staring Qt, so hopefully is a rookie question. Working in Qt Creator 2.7.2, Qt 5, standard desktop app.
Currently my app is one window, with the main window entirely taken up by a console object, with is just a plain text edit, like this:
setCentralWidget(console);
Which of course takes up the entire window. So I added a frame using the UI editor, frame_2. How do I get the console to appear inside the frame, instead of taking up the whole window?

http://qt-project.org/doc/qt-4.8/designer-layouts.html
http://qt-project.org/doc/qt-4.8/layout.html
Your central widget is just QWidget, and then it needs a layout. You drag a layout into it, and there are some buttons across the top of Qt Designer for turning on and off the layout.
When setupUi is called, it already does the setCentralWidget call for you. If you call it yourself you lose all you gained from using Qt Designer.
ui->setupUi(this);
If you are using Qt Designer, you should not edit any generated files. If you edit the .ui file again, it may generate the ui_.h file for you again and fix the problem.
Here is an example of the generated file ui_mainwindow.h:
/********************************************************************************
** Form generated from reading UI file 'mainwindow.ui'
**
** Created: Wed Jul 10 15:48:32 2013
** by: Qt User Interface Compiler version 4.8.4
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
#ifndef UI_MAINWINDOW_H
#define UI_MAINWINDOW_H
#include <QtCore/QVariant>
#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QButtonGroup>
#include <QtGui/QHeaderView>
#include <QtGui/QMainWindow>
#include <QtGui/QMenuBar>
#include <QtGui/QStatusBar>
#include <QtGui/QToolBar>
#include <QtGui/QWidget>
QT_BEGIN_NAMESPACE
class Ui_MainWindow
{
public:
QMenuBar *menuBar;
QToolBar *mainToolBar;
QWidget *centralWidget;
QStatusBar *statusBar;
void setupUi(QMainWindow *MainWindow)
{
if (MainWindow->objectName().isEmpty())
MainWindow->setObjectName(QString::fromUtf8("MainWindow"));
MainWindow->resize(400, 300);
menuBar = new QMenuBar(MainWindow);
menuBar->setObjectName(QString::fromUtf8("menuBar"));
MainWindow->setMenuBar(menuBar);
mainToolBar = new QToolBar(MainWindow);
mainToolBar->setObjectName(QString::fromUtf8("mainToolBar"));
MainWindow->addToolBar(mainToolBar);
centralWidget = new QWidget(MainWindow);
centralWidget->setObjectName(QString::fromUtf8("centralWidget"));
// !!!!! NOTE !!!!! setCentralWidget gets called
MainWindow->setCentralWidget(centralWidget);
statusBar = new QStatusBar(MainWindow);
statusBar->setObjectName(QString::fromUtf8("statusBar"));
MainWindow->setStatusBar(statusBar);
retranslateUi(MainWindow);
QMetaObject::connectSlotsByName(MainWindow);
} // setupUi
void retranslateUi(QMainWindow *MainWindow)
{
MainWindow->setWindowTitle(QApplication::translate("MainWindow", "MainWindow", 0, QApplication::UnicodeUTF8));
} // retranslateUi
};
namespace Ui {
class MainWindow: public Ui_MainWindow {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_MAINWINDOW_H
I also rambled about using Layouts on a previous post:
Add QRadioButton into QWidget without layout
Hope that helps.

Related

QTableWidget: Row does not size properly

I am implementing a small example using a QTableWidget with specific headers.
However, as soon as I run the example the rows do not stretch properly as it is possible to see in the following example (which is the wrong behavior):
After manual resizing I obtain what I am looking for (which is the expected behavior):
prescriptiondialog.h
class PrescriptionDialog : public QDialog
{
Q_OBJECT
public:
PrescriptionDialog();
~PrescriptionDialog();
QPushButton *mAddButton;
QPushButton *mRemoveButton;
QLineEdit *durationEdit;
QLabel *durationLbl;
DrugTable *mTable;
};
#endif // PRESCRIPTIONDIALOG_H
prescriptiondialog.cpp
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QHeaderView>
PrescriptionDialog::PrescriptionDialog()
{
setWindowTitle("Drug Mixer");
mTable = new DrugTable();
mTable->horizontalHeader()->setStretchLastSection(4);
mTable->verticalHeader()->setStretchLastSection(QHeaderView::Interactive);
mTable->show();
QObject::connect(mAddButton, &QPushButton::clicked, mTable, &DrugTable::addCustomRow);
QObject::connect(mRemoveButton, &QPushButton::clicked, mTable, &DrugTable::removeCustomRow);
setLayout(mLay);
show();
}
What I have done so far:
1) I tried to use the headers in the following way, but that did not give the expected behavior.
The problem with this approach is that columns are equally spaced (I am not looking for this specific behavior because I need the user to adjust them as they want) and, most importantly, the row takes the whole space of the application window making the row extremely big.
PrescriptionDialog::PrescriptionDialog()
{
setWindowTitle("Drug Mixer");
mTable = new DrugTable();
mTable->horizontalHeader()->setStretchLastSection(4);
mTable->verticalHeader()->setStretchLastSection(QHeaderView::Interactive);
QHeaderView* header = mTable->horizontalHeader();
header->setSectionResizeMode(QHeaderView::Stretch);
QHeaderView* headerRows = mTable->verticalHeader();
headerRows->setSectionResizeMode(QHeaderView::Stretch);
mTable->show();
}
2) I tried the option of using the horizontalHeader() provided by the QTableWidget but that didn't provide any improvements and actually I obtained the effect of the first screenshot (the "When To Take" column is all compressed until I manually adjust )
PrescriptionDialog::PrescriptionDialog()
{
setWindowTitle("Drug Mixer");
mTable = new DrugTable();
mTable->horizontalHeader()->setStretchLastSection(4);
mTable->verticalHeader()->setStretchLastSection(QHeaderView::Interactive);
mTable->resizeRowsToContents();
mTable->horizontalHeader()->setSectionResizeMode(4, QHeaderView::Stretch);
mTable->show();
}
3) I came across this source, this other source but none of them provided light on how to solve the issue.
4) I dug more into the problem and went through this which is using the property of resizeRowsToContents() which I used in the example but didn't change anything in the final result.
Thanks for shedding light ob this and provide guidance on how to solve the problem.
I tried to make a small example using resizeRowsToContents() and it works well for me.
Tested on Qt 5.15.1 MinGW.
#include "mainwindow.h"
#include <QTableView>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QStandardItemModel>
#include <QHeaderView>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QStandardItemModel *model = new QStandardItemModel{this};
model->appendRow({new QStandardItem{tr("Drug")}, new QStandardItem{}});
QTableView *view = new QTableView{this};
view->setModel(model);
QHBoxLayout *horz_layout = new QHBoxLayout;
horz_layout->addWidget(new QPushButton{tr("Add when"), this});
horz_layout->addWidget(new QPushButton{tr("Remove when"), this});
QStandardItemModel *inner_model = new QStandardItemModel{this};
inner_model->setHorizontalHeaderLabels({tr("Select"), tr("When to take")});
QTableView *inner_view = new QTableView{this};
inner_view->setModel(inner_model);
QWidget *widget = new QWidget;
QVBoxLayout *vert_layout = new QVBoxLayout{widget};
vert_layout->addLayout(horz_layout);
vert_layout->addWidget(inner_view);
view->horizontalHeader()->setStretchLastSection(true);
view->setIndexWidget(model->index(0, 1), widget);
view->resizeRowToContents(0);
this->setCentralWidget(view);
this->resize(500, 500);
}
MainWindow::~MainWindow()
{
}
Result:

Button is not showing on main window even after successful execution of code in Qt

I have tried this code but the button isn't displaying on the main window.
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QGridLayout>
#include<QLabel>
#include<QPushButton>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QPushButton *l=new QPushButton();
l->setText("abc");
QGridLayout *q=new QGridLayout();
q->addWidget(l);
this->setLayout(q);
this->show();
}
MainWindow::~MainWindow()
{
delete ui;
}
I have tried to change the code even by passing enums for alignment but nothing worked.
When you create new Qt widgets Application, the default form (MainWindow ui) is created with centralWidget to put all other widgets. In your code you created the QGridLayout without a parent, typically such layout should be placed in ui->centralWidget (as far as you are not creating another widget to be set as centralWidget), moreover I assume your mainWindow is shown from main.cpp (need not use show()). your code could thus be:
QPushButton *l=new QPushButton();
l->setText("abc");
QGridLayout *q=new QGridLayout(ui->centralWidget);
q-> addWidget(l);
Try adding the widget to the GridLayout with index using addWidget function
void QGridLayout::addWidget(QWidget *widget, int row, int column, Qt::Alignment alignment = ...)
like:
q-> addWidget(l, 0, 0);
P.S. also consider using better names for your variables!

How to have a QTextBrowser to display contents of a QTextEdit?

I am trying to connect QTextEdit to QTextBrowser, so the text browser widget outputs what is entered in text edit widget. As a signal I used textChanged(), and as a slot I used setText(QString). And these two don't have same parameters.
If I used QLineEdit instead of QTextEdit, in that case there is textChanged(QString) function which is compatible with the slot,but I need to make it work with QTextEdit. Here is the code:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtWidgets>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
QWidget * mainWidget=new QWidget(this);
ui->setupUi(this);
QTextEdit * mainTextEdit=new QTextEdit();
QTextBrowser * textDisplay=new QTextBrowser();
connect(mainTextEdit,SIGNAL( textChanged() ),
textDisplay,SLOT( setText(QString) ) );
QHBoxLayout * Alayout=new QHBoxLayout();
Alayout->addWidget(mainTextEdit);
Alayout->addWidget(textDisplay);
mainWidget->setLayout(Alayout);
setCentralWidget(mainWidget);
}
MainWindow::~MainWindow()
{
delete ui;
}
Thankfully, the QTextEdit and QTextBrowser are views onto a QTextDocument model. So, you can simply set the editor's document on the browser. QTextBrowser::setDocument is semantically equivalent to QAbstractItemView::setModel:
textDisplay->setDocument(mainTextEdit->document());
In Qt, there are really two basic model classes: QAbstractItemModel and QTextDocument. A QTextDocument is a model in its own model-view framework. We simply set another view onto the document that the editor operates on. The editor allows modifications to the model, the browser doesn't. It's no different from using the same model on two QListViews, etc.
A QTextEditor is a view with a default model (document). You can replace that default model with one from another view, or even with one that you yourself provide. You could have multiple editors all displaying the same QTextDocument document and allowing editing of it, in parallel. You can also have multiple browsers doing the same.
Complete example:
#include <QApplication>
#include <QTextEdit>
#include <QTextBrowser>
#include <QHBoxLayout>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget window;
QHBoxLayout layout(&window);
QTextEdit edit;
QTextBrowser browser;
layout.addWidget(&edit);
layout.addWidget(&browser);
browser.setDocument(edit.document());
window.show();
return a.exec();
}
I would do it in the following way:
Declare the pointers to the text edit and text browser widgets as member variables in the class,
Create a slot onTextChanged() in MainWindow class that will be called as soon as the text edit is changed and setup the connection as:
connect(mainTextEdit, SIGNAL(textChanged()), this, SLOT(onTextChanged()));
Implement the onTextChanged() slot in the following way:
MainWindow::onTextChanged()
{
QString text = mainTextEdit->toPlainText();
textDisplay->setPlainText(text);
}

QScrollArea derivative is empty if it's created from an .ui file

Consider following simple example:
Area.hh
#pragma once
class Area;
#include <QScrollArea>
class Area : public QScrollArea {
Q_OBJECT
public:
Area (QWidget *_parent = 0);
};
Area.cc
#include "main.hh"
#include "Area.hh"
#include <QLabel>
Area::Area (QWidget *_parent) :
QScrollArea (_parent)
{
QLabel *label = new QLabel ("Show me please");
setWidget (label);
}
This scroll area should show a label inside it. And it does so well if you just create an Area object and show it like this:
Area *area = new Area();
area->show();
However, if you add a QScrollArea with Qt Creator and promote it to Area class, then it shows nothing inside and there are no scrollbars. What can I do to show it properly?
Qt Designer adds an empty widget inside the QScrollArea, overwriting yours.
To prevent that, use a base QWidget instead of a QScrollArea, and promote that widget to an Area class. Qt's Ui compiler won't considered it to be a QScrollArea, so it won't generate a call to setWidget anymore.

How to find global position of text cursor?

I would like to execute a QMenu object at the position of text cursor in a QPlainTextEdit. My problem is that QTextCursor is only define by its position in the Text (index of the character).
How can I find global position of the QTextCursor? Should I use an other object than QTextCursor in order to find the position of the text cursor where I want to open my QMenu?
Thank you by advance.
I've never tried myself, but doesn't QPlainTextEdit::cursorRect() work? It should give you position of the cursor in viewport coordinates. You can then get the viewport using viewport() and map the local position to global using viewport()->mapToGlobal().
I have found similar query to your in some online forum and here's someone suggested the output as
Note: Reference from http://www.unix.com/unix-linux-applications/81388-read-position-mouse-cursor.html, Author of below posting is daggilli, registered user of UNIX online forums. Credit of below posting in its complete form goes to daggilli.
This is the complete code for a Qt application I threw together in about ten minutes (called crosshair) which displays the current mouse coordinates in a window. You might be able to pull enough out of it to be useful. This is Qt 3.1, but Qt 4 is not a great deal different. You will need the Qt development libraries, not just the runtimes. The code comprises two files, crosshair.h and crosshair.cpp.
crosshair.h:
Code:
#ifndef CROSSHAIR_H
#define CROSSHAIR_H
#include <qwidget.h>
#include <qstring.h>
#include <qlabel.h>
#include <qevent.h>
class Crosshair : public QLabel
{
Q_OBJECT
public:
Crosshair(QWidget *parent=0);
protected:
void mousePressEvent(QMouseEvent *);
private:
QTimer *timer;
private slots:
void timerfire();
};
#endif
crosshair.cpp:
Code:
#include <qapplication.h>
#include <qpushbutton.h>
#include <qtimer.h>
#include <qcursor.h>
#include <iostream>
#include "crosshair.h"
using namespace std;
int main(int argc,char **argv)
{
QApplication a(argc,argv);
Crosshair mousepos;
a.setMainWidget(&mousepos);
mousepos.show();
return a.exec();
}
Crosshair::Crosshair(QWidget *parent) : QLabel(parent)
{
setIndent(20);
resize(100,30);
move(1200,200);
setText("0,0");
timer=new QTimer(this);
connect(timer,SIGNAL(timeout()),this,SLOT(timerfire()));
timer->start(50,false);
}
void Crosshair::mousePressEvent(QMouseEvent *)
{
qApp->quit();
}
void Crosshair::timerfire()
{
QPoint p=QCursor::pos();
this->setText(QString().sprintf("%d,%d",p.x(),p.y()));
}
To build this, put both files in a directory called crosshair. cd to that directory and type
Code:
qmake -project
qmake
make
This does nothing more complex than inherit from a QLabel, set a timer to run 20x a second, grab the current cursor coordinates and write them into the label's text. Clicking in the window closes it. I use it for fixing up alignment bugs in JavaScript when I'm laying out objects.
You could open a file in the Crosshair class's constructor to store your data, and use gettimeofday(2) to get a timestamp. Nothing says Qt has to run in GUI mode (you can tell it explicitly not to in the QApplication constructor).
Qt from Trolltech: http://doc.trolltech.com

Resources