common.json文件中appearance.show_scrollbars
common.json对应于代码的common_settings
1.EDA_DRAW_PANEL_GAL类
EDA_DRAW_PANEL_GAL类中定义了绘图的基本要素:
/// Interface for drawing objects on a 2D-surface
KIGFX::GAL* m_gal;
/// Stores view settings (scale, center, etc.) and items to be drawn
KIGFX::VIEW* m_view;
/// Contains information about how to draw items using GAL
std::unique_ptr<KIGFX::PAINTER> m_painter;
1.1类图
EDA_DRAW_PANEL_GAL类包含多个子类,其中SCH_DRAW_PANEL是他的子类之一。
@startuml
class EDA_DRAW_PANEL_GAL {
KIGFX::GAL* m_gal;
}
wxScrolledCanvas <|-- EDA_DRAW_PANEL_GAL
EDA_DRAW_PANEL_GAL *-- GAL
EDA_DRAW_PANEL_GAL <|- SCH_PREVIEW_PANEL
class SCH_DRAW_PANEL{
KIGFX::SCH_VIEW* m_view
KIGFX::WX_VIEW_CONTROLS m_viewControls
}
EDA_DRAW_PANEL_GAL <|-- SCH_DRAW_PANEL
SCH_DRAW_PANEL *-- WX_VIEW_CONTROLS
SCH_DRAW_PANEL *-- SCH_VIEW
WX_VIEW_CONTROLS *-- SCH_DRAW_PANEL
WX_VIEW_CONTROLS *-- SCH_VIEW
SCH_VIEW *-- GAL
@enduml
调用SCH_DRAW_PANEL类的地方:
SCH_DRAW_PANEL* SCH_BASE_FRAME::GetCanvas() const
{
return static_cast<SCH_DRAW_PANEL*>( EDA_DRAW_FRAME::GetCanvas() );
}
SCH_DRAW_PANEL类就是sch_edit_frame位于中央部分的画布,如下图所示,画红框的区域就是SCH_DRAW_PANEL:
从图中我们可以发现一个问题,如果器件长度过长,超出画布的部分没有办法编辑?正常逻辑出发,我们的发布应当有一个滚动条才对。。
滚动时wxScrolledWindow中的图像损坏
1.2 m_gal
/// Interface for drawing objects on a 2D-surface
KIGFX::GAL* m_gal;
关于GAL类的定义:
namespace KIGFX
{
/**
* Abstract interface for drawing on a 2D-surface.
*
* The functions are optimized for drawing shapes of an EDA-program such as BTD-ABS. Most methods
* are abstract and need to be implemented by a lower layer, for example by a Cairo or OpenGL
* implementation. Almost all methods use world coordinates as arguments. The board design is
* defined in world space units for drawing purposes these are transformed to screen units with
* this layer. So zooming is handled here as well.
*
*/
class GAL : GAL_DISPLAY_OPTIONS_OBSERVER
何时创建m_gal?SwitchBackend中可以创建函数:
bool EDA_DRAW_PANEL_GAL::SwitchBackend( GAL_TYPE aGalType )
2.wxScrolledCanvas类
wxScrolledCanvas类是一个wxWidgets C++库中的类,它提供了一个可滚动的绘图区域,可以在其中绘制图形和文本。它继承了wxScrolledWindow类和wxCanvas类的特性,可以自动处理滚动条和滚动事件,使得用户可以通过滚动条来浏览绘图区域的内容。
2.1wxScrolledCanvas滚动条
可能是因为您的wxScrolledCanvas子类没有设置滚动条的大小和位置。
- 请确保您已经正确设置了wxScrolledCanvas的虚拟大小(即可滚动的区域大小),并且将这些值传递给wxScrolledCanvas类的SetVirtualSize()方法。
- 请确保您已经正确设置了wxScrolledCanvas的实际大小(即显示在屏幕上的大小),并且将这些值传递给SetSize方法。
另外,请确保您已经启用了滚动条,可以通过调用wxScrolledCanvas类的SetScrollbars方法来实现。如果问题仍然存在,请检查您的代码是否有其他问题,例如滚动条的位置设置不正确等。
以下是一个简单的wxScrolledCanvas子类的示例代码,它使用了SetScrollbars方法来设置滚动条:
#include <wx/wx.h>
#include <wx/scrolwin.h>
class MyScrolledCanvas : public wxScrolledCanvas
{
public:
MyScrolledCanvas(wxWindow* parent) : wxScrolledCanvas(parent)
{
SetVirtualSize(800, 600); // 设置虚拟大小为800x600
SetScrollbars(10, 10, 80, 60); // 启用滚动条,每次滚动10个像素,总共有80个像素,滚动区域大小为60个像素
}
void OnPaint(wxPaintEvent& event)
{
wxPaintDC dc(this);
dc.SetPen(wxPen(wxColor(255, 0, 0), 2));
dc.DrawLine(0, 0, 800, 600);
}
wxDECLARE_EVENT_TABLE();
};
wxBEGIN_EVENT_TABLE(MyScrolledCanvas, wxScrolledCanvas)
EVT_PAINT(MyScrolledCanvas::OnPaint)
wxEND_EVENT_TABLE()
class MyFrame : public wxFrame
{
public:
MyFrame() : wxFrame(nullptr, wxID_ANY, "My Frame")
{
auto* canvas = new MyScrolledCanvas(this);
auto* vbox = new wxBoxSizer(wxVERTICAL);
vbox->Add(canvas, 1, wxEXPAND);
SetSizer(vbox);
}
};
class MyApp : public wxApp
{
public:
bool OnInit() override
{
auto* frame = new MyFrame();
frame->Show();
return true;
}
};
wxIMPLEMENT_APP(MyApp);
在上面的示例代码中,我们创建了一个名为MyScrolledCanvas的wxScrolledCanvas子类,并在其构造函数中设置了虚拟大小和滚动条。在OnPaint方法中,我们绘制了一条红色的对角线,以便在滚动时可以看到滚动的效果。最后,在MyFrame类中,我们将MyScrolledCanvas添加到了一个wxBoxSizer中,并将其设置为窗口的唯一子控件。
请注意,这只是一个简单的示例代码,您可以根据自己的需求进行修改和扩展。
关于SetScrollbars方法的参数设置,第一个参数是滚动条每次滚动的单位大小,第二个参数是滚动条的初始位置,第三个参数是滚动条的总长度,第四个参数是可见区域的大小。这些参数的设置应该根据您的实际需求来决定,例如可见区域的大小应该根据窗口大小来设置,而滚动条的单位大小和总长度则应根据您的绘图内容来设置。
对于调用SetVirtualSize方法,它是必须在调用SetScrollbars方法之前完成的。
在默认状态下,要显示滚动条,窗口的虚拟大小必须大于窗口的实际大小。
scr->SetVirtualSize(wxSize(2000,2000));
然而,在3.1版本中,这还不足以让滚动条出现。用户还必须设置滚动速率。(对我来说,这感觉像是一个bug,因为似乎应该有一个有效的默认设置。)
scr->SetScrollRate(1, 1);
3.wxScrolledCanvas滚动条Sample
一个wxScrolledCanvas实现滚动条的sample,来自网络
这是一个最小的框架样本,它有一个分割器,左边有位图,右边有一个面板。
// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
// for all others, include the necessary headers (this file is usually all you
// need because it includes almost all "standard" wxWidgets headers)
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#include <wx/scrolwin.h>
#include <wx/splitter.h>
#include <wx/dcbuffer.h>
class MyFrame : public wxFrame
{
public:
MyFrame( wxWindow* parent, int id = wxID_ANY, wxString title = "Demo",
wxPoint pos = wxDefaultPosition, wxSize size = wxDefaultSize,
int style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL );
private:
void OnScrollPaint( wxPaintEvent& event );
wxScrolledCanvas* m_canvas;
wxBitmap m_bitmap;
};
MyFrame::MyFrame( wxWindow* parent, int id, wxString title, wxPoint pos,
wxSize size, int style )
:wxFrame( parent, id, title, pos, size, style )
{
m_bitmap=wxBitmap ("test.png", wxBITMAP_TYPE_PNG );
wxSplitterWindow* m_splitter1
= new wxSplitterWindow( this, wxID_ANY, wxDefaultPosition,
wxDefaultSize, wxSP_LIVE_UPDATE );
m_canvas = new wxScrolledCanvas( m_splitter1, wxID_ANY, wxDefaultPosition,
wxDefaultSize, wxSTATIC_BORDER|wxHSCROLL|wxVSCROLL );
m_canvas->SetScrollRate( 5, 5 );
m_canvas->SetVirtualSize(m_bitmap.GetWidth(), m_bitmap.GetHeight());
m_canvas->SetBackgroundStyle(wxBG_STYLE_PAINT);
m_canvas->Bind( wxEVT_PAINT, &MyFrame::OnScrollPaint , this );
wxPanel* m_panel2 = new wxPanel( m_splitter1, wxID_ANY, wxDefaultPosition,
wxDefaultSize, wxSTATIC_BORDER|wxTAB_TRAVERSAL );
m_splitter1->SplitVertically( m_canvas, m_panel2, GetSize().x/2 );
}
void MyFrame::OnScrollPaint( wxPaintEvent& event )
{
wxAutoBufferedPaintDC dc(m_canvas);
m_canvas->DoPrepareDC(dc);
dc.Clear();
dc.DrawBitmap(m_bitmap,0,0);
}
class MyApp : public wxApp
{
public:
virtual bool OnInit()
{
wxInitAllImageHandlers();
MyFrame* frame = new MyFrame(NULL);
frame->Show();
return true;
}
};
wxIMPLEMENT_APP(MyApp);
要运行此操作,请确保将第35行中的"test.png“更改为计算机上实际图像文件的名称(如果图像文件不是png,则更改wxBITMAP_TYPE_PNG )。
重要的部分是:
将画布的背景样式设置为wxBG_STYLE_PAINT,如第46行所示。
在油漆处理程序中,调用油漆the上的DoPrepareDC方法。
顺便说一下,我的样本中显示的油漆处理程序不是很好。它每次都会绘制整个位图。一种更好的方法是获取更新区域,只重新绘制所需的部分,但我想保持这个简单。
3.1实现局部更新:
上文中说,一种更好的方法是获取更新区域,只重新绘制所需的部分应该怎样实现
要实现只重新绘制所需的部分,可以通过以下步骤来获取更新区域并进行相应的绘制:
-
在窗口的绘图事件处理程序(如OnPaint)中,使用wxPaintDC或wxClientDC对象获取设备上下文(DC)。
-
调用DC的**GetUpdateRegion()**方法,该方法将返回一个表示需要更新的区域的wxRegion对象。
-
遍历更新区域,对于每个矩形区域,进行相应的绘制操作。可以使用DC的绘图函数(如DrawRectangle、DrawLine等)或自定义的绘图函数来实现。
这种方法可以减少不必要的绘制操作,只对需要更新的区域进行绘制,从而提高绘图效率。
以下是一个简单的示例代码,演示了如何获取更新区域并进行相应的绘制:
c
Copy
void MyCanvas::OnPaint(wxPaintEvent& event)
{
wxPaintDC dc(this);
wxRegionIterator updIterator(dc.GetUpdateRegion());
while (updIterator)
{
wxRect rect = updIterator.GetRect();
// 在需要更新的区域进行相应的绘制操作
dc.DrawRectangle(rect);
++updIterator;
}
}
在上述示例代码中,我们使用wxPaintDC对象获取设备上下文,并通过dc.GetUpdateRegion()方法获取更新区域。然后,我们遍历更新区域,并对每个矩形区域进行绘制操作(在这里是绘制矩形)。您可以根据实际需求,在相应的区域内执行您需要的绘制操作。
通过这种方式,您可以只重新绘制需要更新的部分,从而提高绘图效率,并减少不必要的绘制操作。