Создание wxPanel для рисования на - PullRequest
0 голосов
/ 26 апреля 2020

Я пытаюсь создать wxPanel для рисования линий и точек на нем.

Моя программа состоит из следующих элементов: windows:

  1. MyFrame: по умолчанию класс фрейма, который наследуется от 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();

}

enter image description here

Также не имеет отношения к Кто-нибудь знает, как центрировать wxGrid? раздел "Координаты узлов" выглядит не очень хорошо.

Ответы [ 2 ]

2 голосов
/ 26 апреля 2020

Здесь есть несколько проблем.

  1. Вы действительно должны придерживаться символа c константа wxID_ANY вместо использования -1 в строке
Draw_Panel = new wxPanel(this, -1);. 

Таким образом, в очень, очень маловероятном случае изменения wxID_ANY на что-то другое ваш код продолжит работать.


В строке
Draw_Panel ->Connect(wxEVT_PAINT, wxPaintEventHandler(MyFrame::OnPaint));

необходимо указать 2 дополнительных параметра : 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 панели рисуются друг на друге. Чтобы обойти это, добавьте еще 1 sizer к MyFrame

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

. Это создаст этот макет:

enter image description here


Обратите внимание на этот уродливый прямоугольник в левом нижнем углу. Это фон рамки. Чтобы избавиться от этого, вы можете добавить еще 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);

В конечном итоге это дает такой макет:

enter image description here

Вот почему в ответ на ваш предыдущий вопрос была включена часть

Хотя вы можете размещать элементы управления непосредственно в wxFrame из-за «обхода табуляции» и типичных фоновых функций ОС вам лучше использовать wxPanel.


На основе редактирования с помощью блока stati c вокруг панели рисования сначала необходимо создать классификатор box stati c, а затем создать панель как дочерний элемент блока stati c:
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, ни пустой текст c text x, кажется, не служат какой-либо цели, но я предполагаю, что они являются держателями для чего-то, что придет позже.

Наконец, вам нужно изменить конструктор, добавив Draw_StaticBox к Output_and_Draw_vSizer вместо Draw_Panel. ie изменить

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));
1 голос
/ 26 апреля 2020

Обычно события 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);
    }

Чтобы ответить на вопрос - родитель является * Указатель 1006 *, т.е. экземпляр MyFrame. Что правильно - вам просто нужно правильно настроить sizer.

Можете ли вы опубликовать код sizer?

...