Notifying wxSizer of dynamic layout changes - c++

I have the following hierarchy for layout:
wxMDIChildFrame -> wxNotebook ->
wxScrolledWindow -> wxBoxSizer -> wxStyledTextCtrl
GOAL: The wxStyledTextCtrl (CScriptWnd) resizes itself when user adds or deletes a line or presses Shift+Enter to add another CScriptWnd to the wxScrolledWindow.
The following code is when a line is added:
void CScriptWnd::OnNewLineAdded(wxStyledTextEvent& event)
{
long col, line;
PositionToXY(GetInsertionPoint(), &col, &line);
auto ClientSize = GetClientSize();
int Height = ClientSize.GetHeight();
Height += TextHeight(line);
SetClientSize(ClientSize.GetWidth(), Height);
SetMinSize(wxSize(ClientSize.GetWidth(), Height));
Refresh();
//m_ParentWindow->FitInside(); //CScriptWnd gets smaller rather than larger
//m_ParentWindow->Layout(); //CScriptWnd gets smaller rather than larger
//m_ParentWindow->GetGrandParent()->Layout(); //No effect
event.Skip();
}
Most work well such as the CScriptWnd resizes itself, the new script window added to wxScrolledWindow etc...
The problem is that the update to user interface only properly happens when the wxMDIChildFrame is resized using the mouse.
For example, if there are two CScriptWnd and the top one resizes itself, it overlaps with the bottom one
until the wxMDIChildFrame is resized using the mouse. Similar happens for the visibility of scrollbars such that when CScriptWnd client size gets larger the scrollbars only become visible when top-level window resized using the mouse.
Not sure what I am missing.

You probably need
SetMinSize(GetSize());
GetParent()->Layout();

Related

QSplitter disable scrollbar on resizing QLabel

I have added 2 QScrollArea-> QLabel in QSplitter. And am displaying video on both of them. And by default, both of them have same size..
So, when I increase the size of one QLabel by adjusting QSplitter handle, the video takes new allocated space and scales accordingly. However, if I then decrease the size of QLabel, the video would still show up at previous bigger scale and scrollbars would appear.
I instead want to display video without scrollbars and with whatever scale factor that fits current size.
How can this be achieved?
Here is screenshot of my dialog.ui:
And this is my code for displaying image on QLabel
multiews[0] = ui->QImageLabel_view0;
multiews[1] = ui->QImageLabel_view1;
multiews[image_view]->setPixmap(QPixmap::fromImage(qImg).scaled(multiews[image_view]->width(),multiews[image_view]->height(),Qt::KeepAspectRatio));
Update:
I tried to manage desired behaviour by managing
void Dialog::on_splitter_2_splitterMoved(int pos, int index)
{
if(m_videos[0].video_playing){
int w= ui->scrollArea_2->width();
int h=ui->scrollArea_2->height();
ui->QImageLabel_view0->setFixedSize(w-20,h-20);
}
if(m_videos[1].video_playing){
int w= ui->scrollArea_1->width();
int h=ui->scrollArea_1->height();
ui->QImageLabel_view1->setFixedSize(w-20,h-20);
}
}
And am setting back policy to expanding when am using zoom out/zoom in.
void Dialog::PausePlayingVideo()
{ ...
m_scrollarea[active_view]->setWidgetResizable(true);
multiews[active_view]->setMaximumSize(10000,10000);
m_scrollarea[active_view]->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
multiews[active_view]->adjustSize();
multiews[active_view]->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
}
However, the qLabel size is not expanding with this code. Does anybody know, what am doing wrong?

How to appropriately get position of QGraphicsRectItem after drag-release?

I wanted to have an online monitoring system that could tell where the shape is currently, but am getting very weird coordinates of the item, also the dimensions of it get higher by 1 each time I create new one and drag it.
Initial position (map size is 751 by 751, checked by outputting to qDebug(), scene bound to yellow space) :
Dragging it to the left top corner.
As you can see in the beginning it was on (200;200), but after dragging it is on (-201;-196). After deleting it and creating new shape on the same position with the same properties, new shape can't be seen because it is outside of the map, which suggests that edits don't show correct data.
Here is the code of updating the edits:
void CallableGraphicsRectItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
{
QGraphicsRectItem::mouseReleaseEvent(event);
ptr->updateEdits(this);
}
Here is what I managed to cut down into updateEdits():
void MainWindow::updateEdits(QAbstractGraphicsShapeItem* item)
{
//stuff not related to scene
auto posReal = item->scenePos();
auto pos = posReal.toPoint();
//create QString from coordinates
QString coordinate;
coordinate.setNum(pos.x());
ui->leftXEdit->setText(coordinate);
coordinate.setNum(pos.y());
ui->upperYEdit->setText(coordinate);
//get width and height for rect, radius for circle
auto boundingRectReal = item->sceneBoundingRect();
auto boundingRect = boundingRectReal.toRect();
ui->widthEdit->setText(QString::number(boundingRect.width()));
//disables height edit for circles, not really relevant
if (!items[currentShapeIndex].isRect)
{
ui->heightEdit->setDisabled(true);
}
else
{
ui->heightEdit->setDisabled(false);
ui->heightEdit->setText(QString::number(boundingRect.height()));
}
}
Here is how I anchor the QGraphicsScene to the left top corner of the yellow area:
scene->setSceneRect(0, 0, mapSize.width() - 20, mapSize.height() - 20);
ui->graphicsView->setScene(scene);
How can I report the right data to the edits?
You're better off overriding the itemChange method and using the ItemPositionHasChanged notification. You have to set the ItemSendsGeometryChanges flag on the item so that it receives these notifications.
I'm not sure that your item's final position has been set when you're still in the mouseReleaseEvent method. Tracking it in itemChange will ensure that the data is valid, and this kind of thing is what it's for.
Also, note that "pos" is in the item's parent coordinates, and "boundingRect" is in the item's coordinate space. You should use "scenePos" and "sceneBoundingRect" if you want to be sure you're using scene coordinates. If the item doesn't have a parent, then "pos" and "scenePos" will return the same values, but "boundingRect" and "sceneBoundingRect" will generally differ.

Gtk Move window beyond constraints

I am currently writing a gtk program that uses a custom title bar (i.e., it is not being decorated by the window manager). But since using a custom title bar also disables support of dragging the window around, I wrote my custom drag function which moves the window by calling window.move(x, y):
bool on_titlebar_drag(GdkEvent* event)
{
static int drag_x_offset = 0;
static int drag_y_offset = 0;
int x, y;
if (event->type == GDK_BUTTON_PRESS)
{
drag_x_offset = event->button.x;
drag_y_offset = event->button.y;
} else if(event->type == GDK_BUTTON_RELEASE) {
drag_x_offset = 0;
drag_y_offset = 0;
} else if(event->type == GDK_MOTION_NOTIFY) {
x = event->motion.x_root - drag_x_offset;
y = event->motion.y_root - drag_y_offset;
mainWindow.move(x, y);
}
return true;
}
This works just fine except of the fact that it cannot move the window beyond the screen limits, like the normal behaviour for other windows, so you can drag it "out of sight" to make place for others.
I am trying to resize the window smaller as soon as it touches the screen by calling window.resize(width, height) but this is not what I intend to do, because resizing also resizes the window contents to the smaller scale, while I would just like to make its physical size smaller.
I have also tried using set_allocation and size_allocate, these two didnt make any change at all.
My question is, do you know a way to either be able to move the window beyond the screen borders (not totally, but in a way that the window is not fully on-screen), or to change the size of the window without resizing its contents?
If you are using GTK 3.10 or newer you can use gtk_window_set_titlebar
gtk_window_set_titlebar (GtkWindow *window, GtkWidget *titlebar) the only arguments you need are the window that you want to customise and the GtkWidget that will serve as the titlebar. Using GtkHeaderBar is suggested but in your case you can use any custom GtkWidget and get draggable bar which will tug the whole window as would the one from the window manager.

Qt, change widget overlay?

I know I could overlay widgets by just specifying their parent child relation-ship.
But if I have two widgets, say A and B.
At first B is over A and on the bottom left corner of A.
But when a button is clicked, I want A appear over B and on the bottom left corner of B.
How could I implement this without QML?
You can use a combination of QWidget::raise(), QWidget::lower(), QWidget::move(), QWidget::resize().
Pseudo Code:
void slotButtonClicked()
{
// Raize z-index to be "above"
widgetB->raise();
// Update size to small
widgetB->resize( smallWidth, smallHeight );
// Lower z-index to be "below"
widgetA->lower();
// Update size to large
widgetA->resize( largeWidth, largeHeight );
// Move smaller widget to corner
widgetB->move( 0, widgetA->height()-widgetB->height() );
}

Make a QDialog appear in a different screen

The title says it pretty much all:
I have two screens, and each time I create a QDialog it appears in the same screen as its parent.
How can I make it appear in a different screen? Or should I use a different type of top-level widget?
The code I use to create the dialog is:
QDialog my_dialog = new QDialog(this,
Qt::WindowMaximizeButtonHint |
Qt::WindowCloseButtonHint);
...
EDIT:
I have also tried using the QDesktopWidget which gives me a QScreen object that refers to the second screen. But then I don't find how to instruct the QDialog to use that QScreen (setting it as the parent doesn't work).
It is bad, that you edit your question without reading comments :(
// Your screen geometry:
QRect buildScreenGeometry()
{
auto desktop = QApplication::desktop();
QRect virtualRect;
const auto n = desktop->screenCount();
for ( auto i = 0; i < n; i++ )
virtualRect |= desktop->screenGeometry(i);
return virtualRect;
}
// Moving
auto dlg = new QDialog( someParent );
auto newPoint = QPoint( 2000, 0 ); // point on another screen
auto realPos = someParent->mapFromGlobal( newPoint );
dlg->move( realPos );
That's all.
UPDATE:
You should understand, that there are only ONE screen area with COMMON coordinate system, that contains ALL screens.
For example, you have 2 monitors with 800x600 resolution. First (main) monitor is standing left, and second standing right. In this case, coordinate system, that is available for your application is 1600x600. So, if your widget has 100x100 top-left position, on a first monitor, and you want to move it to another, you should call move(900x100); // 900 == screen1.width() + dialog.pos().x(). Then your widget will have 100x100 position on second monitor.
You should read Qt documentation.
You can use move on your QDialog, but be aware that move will set the QDialog position relative to it's parent.
You can get the Main Window's screen position and use that to setup the QDialog position. Just know that you're not guaranteed to have 2 screens on the end user machine.
For more information on move see: http://doc.qt.io/qt-5/application-windows.html#window-geometry