Page 1 of 1

Resize a window full width

Posted: Thu Mar 26, 2020 2:32 pm
by gmapp
Hi,

Simplifying what I need with an example:
I'm trying to implement a button that changes the position and the size of the window.
In the end, the windows should have a size s=(full-width, 250 pixels) and be positioned on the top of my display.
The following code works... but the window is some pixels too small (8 pixels left, 8 right, 8 on bottom).
Is there a bug in my code? In the library?

Code: Select all

void wxTestFrame::OnButton1Click(wxCommandEvent& event){
    int height_main_frame = 250;

    // Get display size
    wxDisplay display(wxDisplay::GetFromWindow(this));
    //wxRect screen = display.GetGeometry();
    //std::cout << screen.width << "x" << screen.height << std::endl;
    wxRect screen = display.GetClientArea();
    std::cout << screen.width << "x" << screen.height << std::endl;

    // Set new size and position for the main window
    this->SetSize(0, 0, screen.width, screen.height);
    
    // Correct size on my enviroment (full screen for testing purpose)
    //this->SetSize(-8, 0, screen.width+16, screen.height+8);
}
OS: Win10
IDE: VS
wx: 3.1.3

Thanks

Re: Resize a window full width

Posted: Thu Mar 26, 2020 4:30 pm
by doublemax
The code looks ok and does work for me. Does display.GetClientArea() return the expected values? Do you have an code that could restrict the size of the window? Try the code in the "minimal" sample that comes with wxWidgets.

Re: Resize a window full width

Posted: Thu Mar 26, 2020 6:00 pm
by gmapp
Yes, display.GetClientArea() returns the expected values (1920x1040)
I tested the code in the minimal sample and I got the same problem...

Code: Select all

 I pasted the code into MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
Unfortunately, I removed an old version of wx library (useful to test) but at this point, it looks like a bug... isn't it?
Have I to run layout() after SetSize()?

Thanks for your help

Re: Resize a window full width

Posted: Thu Mar 26, 2020 7:16 pm
by ONEEYEMAN
Hi,
You can try and see if it helps.

Thank you.

Re: Resize a window full width

Posted: Thu Mar 26, 2020 8:08 pm
by doublemax
I removed an old version of wx library (useful to test) but at this point, it looks like a bug... isn't it?
Very unlikely. Try tracing through the SetSize() call and see what it does.
Have I to run layout() after SetSize()?
No. Layout() is for the sizer algorithm, it has nothing to do with the outer size of a toplevel window.

Re: Resize a window full width

Posted: Thu Mar 26, 2020 9:33 pm
by PB
FWIW, I vaguely remember recently using SetSize() on a wxFrame and the resulting size being a couple of pixels off the requested at least in one dimension (Win10).

Re: Resize a window full width

Posted: Fri Mar 27, 2020 12:16 pm
by gmapp
I ran some tests:
1) On windows wx version 3.1.3 the code doesn't work as aspected
2) On windows wx version 3.0.4 it doesn't work as aspected
3) On Linux wx version 3.1.1 it WORKS :D ! (It was just a test, I need a windows software, unfortunately)

On Windows in debugging mode, I followed step by step the function SetSize(). I arrived at line 1960 of the window.cpp file[1]:

Code: Select all

if ( !::MoveWindow((HWND)hwnd, x, y, width, height, IsShown()) )
The values of the parameters were correct (hwnd, 0, 0, 1920, 250, true).
But I was not able to step into the MoveWindow function with the VS debugger. I'm not a debugging expert, if anyone has suggestions, I'm happy to continue.

Thanks

[1] windows wxWidgets 3.0.4 source

Re: Resize a window full width

Posted: Fri Mar 27, 2020 4:31 pm
by doublemax
I tried under Windows 10 and see it too. I'm almost certain it's done by Windows 10 on purpose, although i can't find any documentation for it. In any case, i don't know what you can do about it.

Re: Resize a window full width

Posted: Fri Mar 27, 2020 5:08 pm
by PB
Is not the issue the invisible border around the window, making it seem smaller than it really is, e.g.
https://stackoverflow.com/questions/319 ... ing-border

Re: Resize a window full width

Posted: Fri Mar 27, 2020 5:12 pm
by doublemax
PB wrote: Fri Mar 27, 2020 5:08 pm Is not the issue the invisible border around the window, making it seem smaller than it really is, e.g.
https://stackoverflow.com/questions/319 ... ing-border
Nice, i guess "invisible borders" was the right keyword for Google to find it ;)

Re: Resize a window full width

Posted: Fri Mar 27, 2020 5:24 pm
by PB
This post may better explain "invisible borders" in Win10
https://stackoverflow.com/a/34143777/7267315

Not sure if it is of any help to the OP...

Re: Resize a window full width

Posted: Thu Apr 02, 2020 8:29 am
by gmapp
Thank you all for your support. As suggested I have solved the problem by increasing, on windows, by 8 pixels to the right, left and bottom.

Re: Resize a window full width

Posted: Thu Apr 02, 2020 9:08 am
by PB
Perhaps instead of hard-coding the values, you could use the way described in the second post I linked. Possibility of these values changing in future Windows versions aside, I would not be surprised if these values were noticeably different when using large DPI scaling such as 200%.

EDIT
Just for the future reference, this seems to work fine

Code: Select all

#include <wx/wx.h>
#include <wx/display.h>

#ifdef __WXMSW__
    #include <dwmapi.h> // needs also to link with dwmapi.lib
#endif // __WXMSW__

class MyFrame : public wxFrame
{
public:
    MyFrame() : wxFrame(nullptr, wxID_ANY, _("Test"))
    {
        wxPanel* mainPanel = new wxPanel(this);
        wxBoxSizer* mainPanelSizer = new wxBoxSizer(wxVERTICAL);
        
        wxButton* button = new wxButton(mainPanel, wxID_ANY, "Fit to Screen");        
        button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &MyFrame::FitToScreen, this);
        mainPanelSizer->Add(button, wxSizerFlags().Border().CenterHorizontal());

        wxTextCtrl* logCtrl = new wxTextCtrl(mainPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
            wxTE_MULTILINE | wxTE_RICH2 | wxTE_READONLY);
        wxLog::SetActiveTarget(new wxLogTextCtrl(logCtrl));
        wxLog::DisableTimestamp();
        mainPanelSizer->Add(logCtrl, wxSizerFlags().Proportion(1).Expand().Border());

        mainPanel->SetSizer(mainPanelSizer);
    }	
private:    
    static wxString wxRectTowxString(const wxRect& r)
    {
        return wxString::Format(_("(left, top; right, bottom): %d, %d; %d, %d"),
            r.GetLeft(), r.GetTop(), r.GetRight(), r.GetBottom());
    }
    
    void FitToScreen(wxCommandEvent&)
    {        
        const wxDisplay display(wxDisplay::GetFromWindow(this));    

        if ( !display.IsOk() )
        {
            wxLogError("Could not create wxDisplay from this window.");
            return;
        }

        const wxRect displayClientRect(display.GetClientArea());
        wxRect windowRect(displayClientRect);        

        wxLogMessage("%s (%dx%d DPI) client rect %s", display.GetName(), 
            display.GetPPI().GetWidth(), display.GetPPI().GetHeight(),
            wxRectTowxString(displayClientRect));        

#ifdef __WXMSW__
        // based on the code from https://stackoverflow.com/a/34143777/7267315
        RECT dwmRect;
        
        if ( SUCCEEDED(::DwmGetWindowAttribute(GetHWND(), DWMWA_EXTENDED_FRAME_BOUNDS,
                       &dwmRect, sizeof(dwmRect))) )
        {
            wxRect borders;
            wxRect windowRectAdjusted(GetRect());

            borders.SetLeft(dwmRect.left - windowRectAdjusted.GetLeft());
            borders.SetTop(dwmRect.top - windowRectAdjusted.GetTop());
            borders.SetRight(windowRectAdjusted.GetRight() - dwmRect.right);
            borders.SetBottom(windowRectAdjusted.GetBottom() - dwmRect.bottom);
            wxLogMessage("Window invisible borders %s", wxRectTowxString(borders));

            windowRectAdjusted = windowRect;
            windowRectAdjusted.Offset(-borders.GetLeft(), -borders.GetTop());
            windowRectAdjusted.SetWidth(windowRect.GetWidth() + borders.GetLeft() + borders.GetRight());
            windowRectAdjusted.SetHeight(windowRect.GetHeight() + borders.GetTop() + borders.GetBottom());            
            wxLogMessage("Adjusted fit-to-screen window rect %s", wxRectTowxString(windowRectAdjusted));

            windowRect = windowRectAdjusted;
        }
#endif // __WXMSW__
        
        SetSize(windowRect);
    }
};


class MyApp : public wxApp
{
public:
    bool OnInit() override
    {
        (new MyFrame())->Show();
        return true;
    }
}; wxIMPLEMENT_APP(MyApp);;
Regarding the difference with DPI scaling:

Code: Select all

\\.\DISPLAY1 (120x120 DPI) client rect (left, top; right, bottom): 0, 0; 2559, 1338
Window invisible borders (left, top; right, bottom): 8, 0; 7, 7
Adjusted fit-to-screen window rect (left, top; right, bottom): -8, 0; 2566, 1345
\\.\DISPLAY2 (96x96 DPI) client rect (left, top; right, bottom): -1680, 195; -1, 1204
Window invisible borders (left, top; right, bottom): 7, 0; 6, 6
Adjusted fit-to-screen window rect (left, top; right, bottom): -1687, 195; 5, 1210

so the difference could be noticeable with higher differences in DPI scalings when hard-coded borders are used...

You can also see (for \\.\DISPLAY2) that for the display client rect neither top nor left are always 0, if one has multiple displays (which is nowadays very common).