创建一个 wxPanel 来绘制

Creating a wxPanel to draw on

我正在尝试创建一个 wxPanel 来绘制线条和点。

我的程序包含以下内容windows:

  1. MyFrame : 默认框架 class 继承自 wxFrame

  2. Final_Layout : wxPanel 的一个实例,父 MyFrame (即这个指针),它包含我所有的控件

现在,我正在尝试创建一个新面板 Draw_Panel,我可以在上面绘图。除了 Final_Layout 使用 wxBoxSizer.

我想附加这个面板

所以,我的第一步是初始化面板,我有以下代码:

   void MyFrame::Initialize_Draw_Input() {

    Draw_Panel = new wxPanel(this, -1); // QUESTION : Who is the parent here? Should it be Final_Layout or "this" pointer?
    Draw_Panel ->Connect(wxEVT_PAINT, wxPaintEventHandler(MyFrame::OnPaint));

}

    void MyFrame::OnPaint(wxPaintEvent& event)
    {
        wxPaintDC dc(Draw_Panel );

        wxCoord x1 = 50, y1 = 60;
        wxCoord x2 = 100, y2 = 60;

        dc.DrawLine(x1, y1, x2, y2);
    }

但是,这不起作用。我想我误解了 wxPanels 的工作方式...我将不胜感激任何帮助/指导

编辑:

根据下面的帮助(非常感谢),我对代码进行了以下更新。但是,现在我无法在面板上绘图:

    void MyFrame::Initialize_Draw_Input() {

    Draw_Panel = new wxPanel(Final_Panel, wxID_ANY,wxDefaultPosition,wxSize(1000,1000),wxTAB_TRAVERSAL,"");
    Draw_StaticBox = new wxStaticBoxSizer(wxHORIZONTAL, Draw_Panel, _T("Cross Section"));
    Draw_Sizer = new wxBoxSizer(wxHORIZONTAL);

   // Draw_Panel->Connect(wxEVT_PAINT, wxPaintEventHandler(MyFrame::OnPaint), NULL, this);

    wxStaticText* x = new wxStaticText(Draw_Panel,wxID_ANY,"");
    Draw_Sizer->Add(x);
    Draw_StaticBox->Add(Draw_Sizer,wxSizerFlags().Expand());
    Draw_Panel->SetSizer(Draw_StaticBox);

    PaintNow();

}

void MyFrame::PaintNow() {

    wxClientDC dc(Draw_Panel);
    Render(dc);

}

void MyFrame::Render(wxDC& dc) {

    wxCoord x1 = 0, y1 = 60;
    wxCoord x2 = 100, y2 = 60;

    dc.DrawLine(x1, y1, x2, y2);

}

我的构造函数:

MyFrame::MyFrame() : wxFrame(NULL, wxID_ANY, "Cross Sectional Properties", wxDefaultPosition, wxSize(1500, 600), wxDEFAULT_FRAME_STYLE & ~(wxRESIZE_BORDER | wxMAXIMIZE_BOX)) {

    wxBoxSizer* Element_and_Node_hSizer = new wxBoxSizer(wxHORIZONTAL);
    wxBoxSizer* Info_and_Data_Input_vSizer = new wxBoxSizer(wxVERTICAL);
    wxBoxSizer* Output_and_Draw_vSizer = new wxBoxSizer(wxVERTICAL);

    wxBoxSizer* Main_hSizer = new wxBoxSizer(wxHORIZONTAL);


    Final_Panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, _T(""));

    Initialize_ProjectInfo_Input(); //Info_Panel, a wxFrame instance is defined here. It contains a wxGrid and other controls for project info input.
    Initialize_Node_Input();        //Node_Panel,  a wxFrame instance is defined here. It contains a wxGrid control for node data input.
    Initialize_Element_Input();     //Element_Panel,  a wxFrame instance is defined here. It contains a wxGrid control for element data input.
    Initialize_Output();            //Out_Panel, a wxFrame instance defined here. It contians a wxGrid for cross sectional properties output. 
    Initialize_Draw_Input();
    InitMenu();                     //Initializes the menu.


    //Combines the Node and element input wxGrid into one sizer - horizontally
    Element_and_Node_hSizer->Add(Node_Panel, wxSizerFlags(1).Expand().Border(wxBOTTOM | wxLEFT |wxRIGHT));
    Element_and_Node_hSizer->Add(Element_Panel, wxSizerFlags(1).Expand().Border(wxBOTTOM | wxRIGHT));

    //Combines the project input and the (Node & Elemetn Input) into one sizer - vertically
    Info_and_Data_Input_vSizer->Add(Info_Panel, wxSizerFlags(1).Expand().Border(wxALL));
    Info_and_Data_Input_vSizer->Add(Element_and_Node_hSizer,wxSizerFlags(1).Expand());

    //Combines output data and draw panel into one sizer - vertically
    Output_and_Draw_vSizer->Add(Out_Panel,wxSizerFlags(1).Border(wxALL));
    Output_and_Draw_vSizer->Add(Draw_Panel, wxSizerFlags(1).Expand().Border(wxLEFT| wxBOTTOM  | wxRIGHT));

    //Combines all into the final layout
    Main_hSizer->Add(Info_and_Data_Input_vSizer);
    Main_hSizer->Add(Output_and_Draw_vSizer);


    SetSizer(Main_hSizer);

    PaintNow();

}

也无关,谁知道如何居中一个wxGrid? "Coordiates of Nodes" 部分看起来不太好。

通常 paibt 事件在适当的 window 中处理,而不是在父 window 中处理。

无论如何,请尝试以下操作:

   void MyFrame::Initialize_Draw_Input()
   {
    Draw_Panel = new wxPanel(this, -1); Should it be Final_Layout or "this" pointer?
    Draw_Panel ->Bind(wxEVT_PAINT, &MyFrame::OnPaint, this);
    }

回答问题 - 父对象是 this 指针,即 MyFrame 实例。这是正确的 - 您只需要适当地设置 sizer。

你能post sizer 代码吗?

这里有多个问题。

  1. 你真的应该坚持使用符号常量 wxID_ANY 而不是在行
  2. 中使用 -1
Draw_Panel = new wxPanel(this, -1);. 

这样,在 wxID_ANY 更改为其他内容的极少数情况下,您的代码将继续工作。


  1. 在行
Draw_Panel ->Connect(wxEVT_PAINT, wxPaintEventHandler(MyFrame::OnPaint));

您需要提供 2 more parameters:userData(几乎总是 NULL)和 eventSink(几乎总是 this)。所以该行应该如下所示:

Draw_Panel ->Connect(wxEVT_PAINT, wxPaintEventHandler(MyFrame::OnPaint),NULL,this);

  1. 你没有显示你的构造函数,所以根据之前的问题,我假设它看起来像这样
MyFrame::MyFrame...

    Info_Panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, _T(""));
    Initialize_Project_Info();
    Initialize_Draw_Input();
}

我假设 Final_Layout 就是前面问题中所谓的 Info_Panel。但是,您可能会注意到这会导致 2 个面板绘制在彼此之上。为了解决这个问题,向 MyFrame 添加 1 个 sizer

MyFrame::MyFrame....

    wxBoxSizer* MainSizer = new wxBoxSizer(wxHORIZONTAL);
    Info_Panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, _T(""));
    Initialize_Project_Info();
    Initialize_Draw_Input();

    Info_Panel->Fit();
    MainSizer->Add(Info_Panel,wxSizerFlags(0));
    MainSizer->Add(Draw_Panel,wxSizerFlags(1).Expand());

    SetSizer(MainSizer);
}

这会生成此布局:


  1. 注意左下方那个丑陋的矩形。那是框架背景。要摆脱它,您可以在 class 中再添加 1 个面板。我将其命名为 framePanel,但您可以随意命名。然后 framePanel 将是您框架的唯一子项,其他 2 个面板将是 framePanel.
  2. 的子项

所以新的构造函数看起来像这样:

MyFrame::MyFrame

    wxBoxSizer* MainSizer = new wxBoxSizer(wxHORIZONTAL);
    framePanel = new wxPanel(this, wxID_ANY);
    Info_Panel = new wxPanel(framePanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, _T(""));
    Initialize_Project_Info();
    Initialize_Draw_Input();

    Info_Panel->Fit();
    MainSizer->Add(Info_Panel,wxSizerFlags(0));
    MainSizer->Add(Draw_Panel,wxSizerFlags(1).Expand());

    framePanel->SetSizer(MainSizer);
}

并且您还应该更改 Draw_Panel 的定义,使新父级像这样:

Draw_Panel = new wxPanel(framePanel, wxID_ANY);

最后这给出了这个布局:

这就是为什么你上一个问题的答案包含了

部分

While you can place controls directly in a wxFrame, because of 'TAB traversal' and a OS's typical background features you better use a wxPanel.


  1. 基于绘制面板周围静态框的编辑,您需要先创建静态框大小调整器,然后将面板创建为静态框的子项:
void MyFrame::Initialize_Draw_Input() {

    Draw_StaticBox = new wxStaticBoxSizer(wxHORIZONTAL, Final_Panel, _T("Cross Section"));
    Draw_Panel = new wxPanel(Draw_StaticBox->GetStaticBox(), wxID_ANY,wxDefaultPosition,wxSize(1000,1000),wxTAB_TRAVERSAL,"");
    Draw_Sizer = new wxBoxSizer(wxHORIZONTAL);

    Draw_Panel->Connect(wxEVT_PAINT, wxPaintEventHandler(MyFrame::OnPaint), NULL, this);

    wxStaticText* x = new wxStaticText(Draw_StaticBox->GetStaticBox(),wxID_ANY,"");
    Draw_Sizer->Add(x);
    Draw_StaticBox->Add(Draw_Panel,wxSizerFlags(1).Expand());
    Draw_StaticBox->Add(Draw_Sizer,wxSizerFlags().Expand());
}

现在 Draw_Sizer 和空的静态文本 x 似乎都没有任何用处,但我认为它们是稍后出现的内容的占位符。

最后,您需要更改构造函数以将 Draw_StaticBox 添加到 Output_and_Draw_vSizer 而不是 Draw_Panel。即改变

Output_and_Draw_vSizer->Add(Draw_Panel, wxSizerFlags(1).Expand().Border(wxLEFT| wxBOTTOM  | wxRIGHT));

Output_and_Draw_vSizer->Add(Draw_StaticBox, wxSizerFlags(1).Expand().Border(wxLEFT| wxBOTTOM  | wxRIGHT));