I'm new to gtkmm and I'm a bit confused about packing and how to make widgets expand.
This is the code I have written:
#include <gtkmm.h>
class GUIWindow : public Gtk::Window
{
public:
GUIWindow()
{
set_title("title");
set_border_width(10);
set_size_request(800, 600);
add(_box_);
_box_.pack_start(_grid_, true, true, 10);
_grid_.add(_frame1_);
_grid_.add(_frame2_);
_grid_.attach_next_to(_frame3_, _frame1_, Gtk::POS_BOTTOM, 2, 1);
_frame1_.set_label("f1");
_frame2_.set_label("f2");
_frame3_.set_label("f3");
_label1_.set_text("Hello world");
_label2_.set_text("this is an example GUI");
_label3_.set_text("some example text");
_frame1_.add(_label1_);
_frame2_.add(_label2_);
_frame3_.add(_label3_);
show_all_children();
}
private:
Gtk::Box _box_;
Gtk::Grid _grid_;
Gtk::Frame _frame1_;
Gtk::Frame _frame2_;
Gtk::Frame _frame3_;
Gtk::Label _label1_;
Gtk::Label _label2_;
Gtk::Label _label3_;
};
int main(int argc, char *argv[])
{
Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "org.gtkmm.examples.base");
GUIWindow guiwindow;
return app->run(guiwindow);
}
I wanted to add 3 labels, each inside their own frame. (Using the frame to see what is going on with the packing.)
I initially added a grid to my window and filled it with the 3 frames, filling each of those with a label. However, the grid did not expand to fill the window. So I tried putting the grid inside a box, but the box also does not expand to fill the window.
I've searched the documentation and the web for a solution, but didn't find one. I think I've just not quite understood how the packing works.
How can I get the "box" object to fill the entire window, so that when the window resizes the box also resizes, and the frames resize with the grid which resizes with the box. (The labels presumably will not resize.)
This is probably what you are looking for
set_halign(Align align)
set_valign(Align align)
set_hexpand(bool expand = true)
set_vexpand(bool expand = true)
An example would be:
for (const auto &child : _grid_.get_children()) {
child->set_hexpand(true);
child->set_halign(Gtk::ALIGN_FILL);
child->set_vexpand(true);
child->set_valign(Gtk::ALIGN_FILL);
}
Related
I am adding a compass to the top right corner of a QGraphicsView like so:
ui.compass = new QLabel(viewport());
ui.compass->setPixmap(pm);
ui.compass->setContentsMargins(viewport()->width() - pm.width() - 2, 2, 0, 0);
When the QGraphicsView is resized, I simply reset the left margin (the same code as the last line above) to keep it on the right.
The problem happens when I resize the QGraphicsView to any width wider than when the application started, in which case, the compass is clipped (as seen in the screenshot below) and eventually disappears completely, as if there is an invisible curtain is slides behind. When resizing smaller than the initial size, all works as expected. After resizing smaller, it can be resized larger also without issue until reaching that initial width again.
Edit: the application saves the geometry on close and restores next start up. If I resize the window to be larger, such that compass is not visible, close the application and start it again, the graphics view starts as the larger size and the compass is visible, until I try to resize wider again.
Edit 2: added minimum working example. Just resize the application wider than start up and watch the compass image disappear.
#include <QApplication>
#include <QMainWindow>
#include <QGraphicsView>
#include <QLabel>
#include <QPixmap>
class MyGraphicsView : public QGraphicsView
{
public:
MyGraphicsView()
: pm(":/images/Compass.svg")
, compass(new QLabel(viewport()))
{
compass->setPixmap(pm);
}
private:
void resizeEvent(QResizeEvent* event) override
{
QGraphicsView::resizeEvent(event);
QMargins margins = compass->contentsMargins();
margins.setLeft(viewport()->width() - pm.width() - 2);
compass->setContentsMargins(margins);
}
QLabel* compass;
QPixmap pm;
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMainWindow win;
win.setCentralWidget(new MyGraphicsView());
win.show();
return app.exec();
}
I want to change the Icon of a Toolbutton after the Toolbutton was clicked.
My problem is, when i use the Toolbutton method set_icon_widget() , the current Icon disappears, but the new one doesn't show up. The Toolbutton is still there, but it has no Icon anymore.
Here is my Code:
#include <gtkmm.h>
class MainWindow : public Gtk::Window{
public:
MainWindow();
private:
void clicked();
Gtk::Box m_vbox;
Gtk::Image image;
Gtk::Image image_clicked;
Gtk::Toolbar toolbar;
Gtk::ToolButton icon;
Gtk::ToolButton connected;
};
MainWindow::MainWindow() :
image(Gdk::Pixbuf::create_from_file( "network-transmit-receive.svg")),
image_clicked(Gdk::Pixbuf::create_from_file("network-offline.svg")){
//Window Configuration
set_title("Tool Button Icon Test");
set_default_size(400, 200);
set_position(Gtk::WIN_POS_CENTER);
icon.set_icon_widget(image);
connected.set_icon_widget(image_clicked);
icon.signal_clicked().connect( sigc::mem_fun(*this, &MainWindow::clicked));
toolbar.set_toolbar_style(Gtk::TOOLBAR_ICONS);
toolbar.set_icon_size(Gtk::ICON_SIZE_SMALL_TOOLBAR);
toolbar.set_vexpand_set(false);
toolbar.add(icon);
m_vbox.set_orientation(Gtk::ORIENTATION_VERTICAL);
m_vbox.pack_start(toolbar, Gtk::PACK_SHRINK, 0);
add(m_vbox);
show_all_children();
}
void MainWindow::clicked(){
icon.set_icon_widget(image_clicked);
}
int main (int argc, char *argv[])
{
Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "de.example.Toolbutton-Test");
MainWindow mainwindow;
//Shows the window and returns when it is closed.
return app->run(mainwindow);
}
I also tried to remove the current ToolButton and to add a new one with the different Icon, but than the current Toolbutton is removed and the new one is not drawn :-/
Can somebody help me please?
I just found the answer by myself. I can change the icon of the MenuButton by setting a new image to the image object of the MenuButton.
The clicked Method looks like this now:
void MainWindow::clicked(){
image.set(Gdk::Pixbuf::create_from_file("network-offline.svg"));
}
When I set mainwindow to fullscreen() , title bar disappears, thats what I want. But when a dialog is opened main window title bar appears again, which is undesirable in my case.I have tried setting several Qt::windowflags but they dont work.Any help will be greatly appreciated.
Quick answer here, you have to do something like this
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyMainWindow window;
window.setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
window.show();
}
PS: What I gather from the net is that, the results are a bit ambiguous. Do let us know the result
To move the dialog in the centre:
1.Calling widget should pass the centre co-ordinates to the dialog window.
I have done it by passing co-ordinates by calling a dialog funuction.
In widget.cpp:
dialog->centre(this->width()/2,this->height()/2);
2.In the dialog.cpp :
`centre(int x,int y)
{
width =x; //store in some global variable
height=y;
}`
3.In the show event of dialog.cpp:
this->move(width,height);
Done. It will place the dialog in the centre of the widget.
#include <QtGui>
int main(int argc, char** argv)
{
QApplication app(argc, argv);
// first
QMessageBox box(0);
box.setText("short text");
box.setWindowTitle("looooooooooooooooong text");
box.setMinimumSize(800, 0);
box.exec();
// second
//QMessageBox::warning(0, "looooooooooooooooong text", "short text");
return app.exec();
}
Both approaches produce this messagebox, where title is not displayed properly. I have tried to resize dialog widget by it doesn't help. How can I force QMessageBox to display whole title?
As a workaround I can add trailing spaces to title text but I think there should be better solution.
aminasya#aminasya-desktop:~/qt$ qmake --version
QMake version 2.01a
Using Qt version 4.8.6 in /usr/lib/x86_64-linux-gnu
I tried to create QMessageBox with constructor which qt help mentioned in qmessagebox.cpp but it didnt worked for me too.
For some reason QMessageBox adjust size to fit the window title doesn't work. However you can adjust MessageBox size by creating your own sublclass of QMessageBox.
Please see example below;
class MyMessageBox : public QMessageBox
{
public:
explicit MyMessageBox(QWidget *parent = 0) : QMessageBox(parent) { }
MyMessageBox(const QString &title, const QString &text, Icon icon,
int button0, int button1, int button2,
QWidget *parent = 0,
Qt::WindowFlags f = Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint) :
QMessageBox(title, text, icon, button0, button1, button2, parent, f) { }
static void about(QString title, QString text)
{
MyMessageBox aboutBox(title, text, QMessageBox::Information, 0, 0, 0, NULL);
aboutBox.setText(title);
aboutBox.setText(text);
QIcon icon = aboutBox.windowIcon();
QSize size = icon.actualSize(QSize(64, 64));
aboutBox.setIconPixmap(icon.pixmap(size));
aboutBox.exec();
}
void showEvent(QShowEvent *event)
{
QMessageBox::showEvent(event);
QWidget *textField = findChild<QWidget *>("qt_msgbox_label");
if (textField != NULL)
{
// getting what ever my system has set for the window title font
QFont font = QFont("Ubuntu Bold", 11);
// you might want to make it more generic by detecting the actuall font
// or using smth like this:
//QFont font = QApplication::font("QWorkspaceTitleBar");
QFontMetrics fm(font);
int width = qMax(fm.width(windowTitle()) + 50, textField->minimumWidth());
textField->setMinimumWidth(width);
}
}
};
It appears that QMessageBox, when launched with exec() checks the length of the body text and automatically adjusts the size, ignoring the fact that the title text may be longer. Though not ideal, you can change it just afterwards with a QTimer, as demonstrated here:
QMessageBox* box = new QMessageBox;
box->setText("short text");
box->setWindowTitle("looooooooooooooooong text");
QTimer* pTimer = new QTimer;
pTimer->setSingleShot(true);
QObject::connect(pTimer, &QTimer::timeout, [=](){
box->setMinimumWidth(400);
pTimer->deleteLater();
});
pTimer->start(0);
box->exec();
Since this occurs after the message box is launched, the change in size is visible.
The better solution would simply be to create your own MessageBox, derived from QDialog. After all, the QMessageBox class is just a convenience widget.
Since exec() and show() both override your minimum size based on the contents of the box's text, the simple solution is not to use exec() and to set the minimum size after the box has been shown. In any case, you should never use exec() in dialogs anyway.
Note: Window titles are non-portable. Your UI must still make sense without a window title. For example, on OS X the message box window titles are invisible.
#include <QApplication>
#include <QMessageBox>
#include <QDebug>
int main(int argc, char** argv)
{
QApplication app(argc, argv);
QMessageBox box;
box.setText("short text");
box.setWindowTitle("looooooooooooooooong text");
box.show();
box.setMinimumSize(qMax(box.minimumWidth(), 800), box.minimumHeight());
return app.exec();
}
Since the message box width is adjusted to the width of the text, a simple answer seems to be to pad the text string with spaces:
QString title = "This is a looooooooooooooooooooooooong title";
QString txt = "Short Text";
QMessageBox box;
box.setWindowTitle(title);
int titleLen = title.length();
int txtLen = txt.length();
if (txtLen < titleLen)
{
int diff = titleLen - txtLen;
txt.resize(titleLen + (diff * 2),' '); // diff * 2 is extra padding;
}
box.setText(txt);
box.exec();
You can see I kludged the padding length because of variable width fonts. But hey, the kludge works for me.
There is a Qt application. GL-window created into this application by calling XCreateWindow function and I can't edit it.
I need put Xwindow in QWidget inside my Qt applications.
In the documentation:
void QWidget::create ( WId window = 0, bool initializeWindow = true,
bool destroyOldWindow = true ) [protected]
Creates a new widget window if the window is 0, otherwise sets the widget ' s window to window.Initializes the window sets the geometry etc.) if initializeWindow is true. If initializeWindow is false, no initialization is performed. This parameter only makes sense if window is a valid window.
...
For verifying the result of function QWidget::create there is the following code:
class ParentWindow : public QWidget
{
Q_OBJECT
public:
ParentWindow(WId id)
{
create(id);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QPushButton* button = new QPushButton("MEGA BUTTON");
button->show();
ParentWindow w(button->winId());
w.show();
return a.exec();
}
When application start a single blank window appears. Although expected window containing a button (or to be a button).
How can I put X11 window into my QWidget?
The problem was resolved:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Display* display = XOpenDisplay(NULL);
XSynchronize(display, True);
XSetErrorHandler(myErrorHandler);
Window x11root = XDefaultRootWindow(display);
int x = 500;
int y = 500;
unsigned int width = 150;
unsigned int height = 150;
unsigned int borderWidth = 0;
long colorBlue = 0xff0000ff;
Window x11w = XCreateSimpleWindow(display, x11root, x, y,
width, height, borderWidth, 1 /*magic number*/, colorBlue);
QWidget w;
w.resize(300, 300);
w.show();
XReparentWindow(display, x11w, w.winId(), 0, 0);
XMapWindow(display, x11w); // must be performed after XReparentWindow,
// otherwise the window is not visible.
return a.exec();
}
To solve the problem through a widget ParentWindow failed - xwindow is embedded in QWidget, but have problems with resizing the window and closing it (it doesn't close).
QX11EmbedContainer could be what you need.
Let Qt create your Window and then use the Qt X11 Drawable with your X11/GL code.
With OpenGL and Qt you must use the Qt OpenGL context, if Qt is rendering using OpenGL. Just be aware that Qt expects the OpenGL state to be put back to what it was when it last used it.
You can get access to the Drawable using QX11Info (also check Compiler does not see QX11Info as this covers a common problem when including X11 with Qt).
The way Qt provides access to both X11 and OpenGL seems to change between major and minor versions so you may need to do a little bit of digging.
I know that the above works with Qt5.1 upto 5.5. Qt5.6 has problems with this approach that I've not yet resolved.
You should not touch window IDs in your first Qt program. Window IDs are a low level concept and a Qt programmer normally needs them only to do something outside of the Qt framework. Managing widgets as children of other widgets is not that kind of task.
I recommend you start with one of the tutorials. Look in particular here to see how you make a widget a child of another widget.