创建一个 wxPanel 来绘制
Creating a wxPanel to draw on
我正在尝试创建一个 wxPanel 来绘制线条和点。
我的程序包含以下内容windows:
MyFrame : 默认框架 class 继承自 wxFrame
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 代码吗?
这里有多个问题。
- 你真的应该坚持使用符号常量
wxID_ANY
而不是在行 中使用 -1
Draw_Panel = new wxPanel(this, -1);.
这样,在 wxID_ANY 更改为其他内容的极少数情况下,您的代码将继续工作。
- 在行
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);
- 你没有显示你的构造函数,所以根据之前的问题,我假设它看起来像这样
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);
}
这会生成此布局:
- 注意左下方那个丑陋的矩形。那是框架背景。要摆脱它,您可以在 class 中再添加 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);
最后这给出了这个布局:
这就是为什么你上一个问题的答案包含了
部分
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.
- 基于绘制面板周围静态框的编辑,您需要先创建静态框大小调整器,然后将面板创建为静态框的子项:
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));
我正在尝试创建一个 wxPanel 来绘制线条和点。
我的程序包含以下内容windows:
MyFrame : 默认框架 class 继承自 wxFrame
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 代码吗?
这里有多个问题。
- 你真的应该坚持使用符号常量
wxID_ANY
而不是在行 中使用 -1
Draw_Panel = new wxPanel(this, -1);.
这样,在 wxID_ANY 更改为其他内容的极少数情况下,您的代码将继续工作。
- 在行
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);
- 你没有显示你的构造函数,所以根据之前的问题,我假设它看起来像这样
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);
}
这会生成此布局:
- 注意左下方那个丑陋的矩形。那是框架背景。要摆脱它,您可以在 class 中再添加 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);
最后这给出了这个布局:
这就是为什么你上一个问题的答案包含了
部分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.
- 基于绘制面板周围静态框的编辑,您需要先创建静态框大小调整器,然后将面板创建为静态框的子项:
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));