Resize a window full width Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
gmapp
Earned a small fee
Earned a small fee
Posts: 14
Joined: Wed Jan 24, 2018 4:39 pm

Resize a window full width

Post by gmapp » Thu Mar 26, 2020 2:32 pm

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

User avatar
doublemax
Moderator
Moderator
Posts: 14613
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Resize a window full width

Post by doublemax » Thu Mar 26, 2020 4:30 pm

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.
Use the source, Luke!

gmapp
Earned a small fee
Earned a small fee
Posts: 14
Joined: Wed Jan 24, 2018 4:39 pm

Re: Resize a window full width

Post by gmapp » Thu Mar 26, 2020 6:00 pm

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

ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 3893
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: Resize a window full width

Post by ONEEYEMAN » Thu Mar 26, 2020 7:16 pm

Hi,
You can try and see if it helps.

Thank you.

User avatar
doublemax
Moderator
Moderator
Posts: 14613
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Resize a window full width

Post by doublemax » Thu Mar 26, 2020 8:08 pm

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.
Use the source, Luke!

PB
Part Of The Furniture
Part Of The Furniture
Posts: 2230
Joined: Sun Jan 03, 2010 5:45 pm

Re: Resize a window full width

Post by PB » Thu Mar 26, 2020 9:33 pm

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).

gmapp
Earned a small fee
Earned a small fee
Posts: 14
Joined: Wed Jan 24, 2018 4:39 pm

Re: Resize a window full width

Post by gmapp » Fri Mar 27, 2020 12:16 pm

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

User avatar
doublemax
Moderator
Moderator
Posts: 14613
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Resize a window full width

Post by doublemax » Fri Mar 27, 2020 4:31 pm

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.
Use the source, Luke!

PB
Part Of The Furniture
Part Of The Furniture
Posts: 2230
Joined: Sun Jan 03, 2010 5:45 pm

Re: Resize a window full width

Post by PB » 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

User avatar
doublemax
Moderator
Moderator
Posts: 14613
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Resize a window full width

Post by doublemax » Fri Mar 27, 2020 5:12 pm

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 ;)
Use the source, Luke!

PB
Part Of The Furniture
Part Of The Furniture
Posts: 2230
Joined: Sun Jan 03, 2010 5:45 pm

Re: Resize a window full width

Post by PB » Fri Mar 27, 2020 5:24 pm

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...

gmapp
Earned a small fee
Earned a small fee
Posts: 14
Joined: Wed Jan 24, 2018 4:39 pm

Re: Resize a window full width

Post by gmapp » Thu Apr 02, 2020 8:29 am

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.

PB
Part Of The Furniture
Part Of The Furniture
Posts: 2230
Joined: Sun Jan 03, 2010 5:45 pm

Re: Resize a window full width

Post by PB » Thu Apr 02, 2020 9:08 am

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).

Post Reply