GetSize() of a new Frame's MenuBar 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
User avatar
Artifact2238
Earned a small fee
Earned a small fee
Posts: 23
Joined: Mon May 28, 2018 2:43 am

GetSize() of a new Frame's MenuBar

Post by Artifact2238 »

Hello folks,

When I run my program, the following error appears in the Log Window.
In file ./include/wx/msw/private.h at line 339: 'GetWindowRect' failed with error 0x00000578 (Invalid window handle.).
The call that produces this is Line 118 in MyFrame constructor.

Code: Select all

    int fileMenuBarSize_height = menuBar->GetSize().GetHeight();
My question is: Why does GetWindowRect fail here? What's wrong? I am running Windows 7.

And, how do I mitigate this problem? Should I call things in a different way? Thank you!

Here is my minimal, one-file example. I hope it is easy to test.
Go to File --> Log Window to see the error I mentioned.

Code: Select all

// For compilers that support precompilation, includes "wx/wx.h".

#include "wx/wxprec.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

#ifndef WX_PRECOMP
    #include "wx/wx.h"
#endif


#ifndef MAIN_APP_H
#define MAIN_APP_H

// Define a new application
class MyApp : public wxApp
{
public:
    MyApp(){};
    bool OnInit() wxOVERRIDE;
};

// The main frame class
class MyFrame : public wxFrame
{
  public:
    MyFrame(const wxString& title);

    void OnQuit(wxCommandEvent& event);
#if wxUSE_LOGWINDOW
    void OnLogWindow(wxCommandEvent& event);
#endif // wxUSE_LOGWINDOW

  private:
#if wxUSE_LOGWINDOW
    wxLogWindow* m_LogWin;
#endif // wxUSE_LOGWINDOW

    wxDECLARE_EVENT_TABLE();
};

// IDs for the controls and the menu commands
enum
{
    MyFrame_Quit  = wxID_EXIT,
    MyFrame_About = wxID_ABOUT,
    MyFrame_LogW  = wxID_HIGHEST + 10,
};

#endif // MAIN_APP_H


wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
    EVT_MENU(MyFrame_Quit,  MyFrame::OnQuit)
#if wxUSE_LOGWINDOW
    EVT_MENU(MyFrame_LogW,  MyFrame::OnLogWindow)
#endif // wxUSE_LOGWINDOW
wxEND_EVENT_TABLE()

wxIMPLEMENT_APP(MyApp);

// 'Main program' equivalent: the program execution "starts" here
bool MyApp::OnInit()
{
    if (!wxApp::OnInit())
        return false;

    // create the main application window
    MyFrame* frame = new MyFrame("wxWidgets MyFrame Sample");

    // As of October 2015 GTK+ needs the frame to be shown before we call SetCurrent()
    frame->Show(true);

    return true;
}

const int frame_size = 512;

// frame constructor
MyFrame::MyFrame(const wxString& title)
       : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition,
                 wxSize(frame_size, frame_size))
{

#if wxUSE_MENUS
    // create a menu bar
    wxMenu *fileMenu = new wxMenu;

#if wxUSE_LOGWINDOW
    fileMenu->Append(MyFrame_LogW, "&Log window", "Open the log window");
    fileMenu->AppendSeparator();
#endif // wxUSE_LOGWINDOW
    fileMenu->Append(MyFrame_Quit, "E&xit\tAlt-X", "Quit this program");

    // now append the freshly created menu to the menu bar...
    wxMenuBar *menuBar = new wxMenuBar();
    menuBar->Append(fileMenu, "&File");

    // ... and attach this menu bar to the frame
    SetMenuBar(menuBar);
#endif // wxUSE_MENUS

#if wxUSE_LOGWINDOW
    //Open a log window, don't show it though
    m_LogWin = new wxLogWindow(NULL, "MyFrame log window", false, false);
    wxLog::SetActiveTarget(m_LogWin);
#endif // wxUSE_LOGWINDOW

    // !!!!!!!!!!!!!!!!!!!!!!!
    // !!!
    // !!!  causing error
    // !!!  In file ./include/wx/msw/private.h at line 339:
    // !!!  'GetWindowRect' failed with error 0x00000578 (Invalid window handle.).
    // !!!
    // !!!!!!!!!!!!!!!!!!!!!!!!
    int fileMenuBarSize_height = menuBar->GetSize().GetHeight();
}

// event handlers
void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
    Close(true); // true is to force the frame to close
}

#if wxUSE_LOGWINDOW
void MyFrame::OnLogWindow(wxCommandEvent& WXUNUSED(event))
{
    if (m_LogWin->GetFrame()->IsIconized())
        m_LogWin->GetFrame()->Restore();

    if (!m_LogWin->GetFrame()->IsShown())
        m_LogWin->Show();

    m_LogWin->GetFrame()->SetFocus();
}
#endif // wxUSE_LOGWINDOW
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: GetSize() of a new Frame's MenuBar

Post by doublemax »

Although wxMenuBar derives from wxWindow, it's only a dummy window under Windows. It's not a "real" window and has no HWND.

For what purpose do you need to know its height?
Use the source, Luke!
User avatar
Artifact2238
Earned a small fee
Earned a small fee
Posts: 23
Joined: Mon May 28, 2018 2:43 am

Re: GetSize() of a new Frame's MenuBar

Post by Artifact2238 »

Thank you for the reply, I didn't know you needing a proper HWND to determine the height of a component.

After doing more research based on your response, I think I solved my issue.

But to answer your question:
For what purpose do you need to know its height?
I have an image that is 512x512 pixels. I want it to be displayed exactly at a 512x512 pixel resolution on the screen. No clipping or stretching.

When I construct the MyFrame object (inherits from wxFrame), I do the following:

Code: Select all

const int frame_size = 512;
MyFrame::MyFrame(const wxString& title)
       : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition,
                 wxSize(frame_size, frame_size))
This makes the overall window 512x512 px, which is what I expect. But when we account for the border of the window's frame, my status bar, and my menu bar, it makes the area of the actual workable area within the frame be only 496x431 px.

What I was trying to was making this workable area be 512x512 px, making the overall frame be greater than that.

For some reason, I thought I had to do something like this:

Code: Select all

wxFrame::SetClientSize(frame_size + fileMenuBarSize_height + menuBarSize_height, frame_size);
But now, after doing more research, I have figured out that simply doing

Code: Select all

wxFrame::SetClientSize(new_width, new_height);
Makes the working area be 512x512.

Guess my problem's solved then, thank you again for your time.
Post Reply