【问题标题】:Creating a wxPanel to draw on创建一个 wxPanel 来绘制
【发布时间】:2020-04-26 04:18:23
【问题描述】:

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

我的程序由以下窗口组成:

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

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

现在,我正在尝试创建一个新面板 Draw_Panel,我可以在上面进行绘图。我想使用 wxBoxSizer 在 Final_Layout 之外附加这个面板。

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

   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 居中吗? “节点坐标”部分看起来不太好。

【问题讨论】:

    标签: wxwidgets


    【解决方案1】:

    这里有多个问题。

    1. 你真的应该坚持使用符号常量 wxID_ANY 而不是在行中使用 -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. 请注意左下方那个丑陋的矩形。那是框架背景。要摆脱它,您可以在班级中再添加 1 个面板。我会叫它framePanel,但它可以叫任何你想要的名字。然后framePanel 将是您框架的唯一子级,其他 2 个面板将是framePanel 的子级。

    所以新的构造函数可能如下所示:

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

    最后这给出了这个布局:

    这就是为什么您上一个问题的答案包含该部分

    虽然您可以将控件直接放在 wxFrame 中,但由于“TAB 遍历”和操作系统的典型背景功能,您最好使用 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));
    

    【讨论】:

    • 谢谢,我对面板及其与框架的交互有了更好的了解
    • 嗯,我通过在面板周围添加了一个静态 box sizer 对代码进行了一些更改,现在,我无法使用它。我附上了我的代码。你知道为什么会这样吗?我在 OP 中发布了代码
    • 除非我遗漏了什么,否则您注释掉了对绘制处理程序的 Connect 调用,并添加了使用客户端 dc 绘制的代码。这将执行一次绘图,但下次刷新面板时将覆盖任何绘图。为确保每次刷新面板时都完成绘图,您需要使用paint事件并使用paint dc进行绘制。
    • 你建议的原始代码由于某种原因停止了画线,这就是我尝试使用 wxClientDC 的原因。但即使是这个控件也不会绘制。
    • 我现在明白了。在您发布的代码中,您创建了一个静态框,而不是覆盖绘图面板。我认为你需要以相反的顺序 - 创建静态框尺寸器,然后在静态框上创建面板。我编辑了答案以添加第 5 项,以举例说明如何执行此操作。
    【解决方案2】:

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

    无论如何,请尝试以下方法:

       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。

    你能发布sizer代码吗?

    【讨论】:

    • 我正在进一步调试我的代码,我可以在代码再次运行后发布它lol
    猜你喜欢
    • 2014-10-12
    • 1970-01-01
    • 1970-01-01
    • 2023-01-18
    • 1970-01-01
    • 1970-01-01
    • 2021-12-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多