ScrolledWindow

本文详细介绍了GTKmm中的ScrolledWindow组件,解释了如何通过set_policy()方法来控制滚动条的显示策略,并提供了一个简单的示例,展示了如何将多个按钮放入滚动窗口中。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

学习gtkmm有几周了,英语太烂了,硬着头皮边看边记,还没把握,发上来,大家斧正

7.1.3. ScrolledWindow

ScrolledWindow widgets create a scrollable area. You can insert any type of widget into a ScrolledWindow window, and it will be accessible regardless of its size by using the scrollbars. Note that ScrolledWindow is not a Gtk::Window despite the slightly misleading name.

滚动窗口(ScrolledWindow控件建立一个滚动区。你可以在滚动窗口中插入任何类型控件,借助滚动条访问,不受大小限制。注意,虽然叫ScrolledWindow,但它不是一个Gtk::window

Scrolled windows have scrollbar policies which determine whether the Scrollbars will be displayed. The policies can be set with the set_policy() method. The policy may be one of Gtk::POLICY_AUTOMATIC or Gtk::POLICY_ALWAYS. Gtk::POLICY_AUTOMATIC will cause the scrolled window to display the scrollbar only if the contained widget is larger than the visible area. Gtk::POLICY_ALWAYS will cause the scrollbar to be displayed always.

滚动窗口(ScrolledWindow)有一定的显示滚动条(Scrollbars)的方式。显示方式可由set_policy()方法设置。设置值可为Gtk::POLICY_AUTOMATIC Gtk::POLICY_ALWAYSGtk::POLICY_AUTOMATIC 设置滚动条在子控件的大小超出显示区域时显示, Gtk::POLICY_ALWAYS设置滚动条总是显示。

参考

§  7.1.3.1. 示例

7.1.3.1. 示例

Here is a simple example that packs 100 toggle buttons into a ScrolledWindow. Try resizing the window to see the scrollbars react.

这里是一个在滚动窗中放入100个开关按钮的简单例子。试着改变窗口的大小看滚动条的反应。

7-3 ScrolledWindow

源代码

 

 

# 📘 第二章:wxWidgets 核心可视化组件 ## 2.2 wxPanel - 容器控件 --- ### 🔍 章节概述 **`wxPanel`** 是一个轻量级的窗口容器控件,常用于组织和管理其他控件。它继承自 `wxWindow`,支持布局管理、绘图、背景色设置等高级功能,是构建 GUI 界面结构的重要组成部分。 该控件适用于以下常见场景: - 组织多个控件形成逻辑区域(如“用户信息”、“高级设置”) - 实现局部布局管理 - 自定义绘制界面元素(如图表、动画) - 嵌套使用实现复杂的 UI 分区设计 本节将讲解: - `wxPanel` 的基本用途与创建方法 - 如何嵌套其他控件并进行布局 - 设置背景颜色与样式 - C++ 和 Python 示例代码 - 与 `wxSizer` 的配合使用技巧 - 自定义绘制面板内容的方法 --- ### **属性** | 属性名 | 类型 | 说明 | |--------|------|------| | `Parent` | `wxWindow*` | 父容器指针 | | `BackgroundColour` | `wxColour` | 背景色 | ### **方法** | 方法名 | 返回值 | 说明 | |--------|--------|------| | `SetBackgroundColour(const wxColour& colour)` | `void` | 设置背景色 | | `GetClientSize()` | `wxSize` | 获取客户区尺寸 | ### **事件** | 事件类型 | 说明 | |----------|------| | `无` | 仅用于布局容器,无交互事件 | --- ## ✅ C++ 实现代码(wxWidgets) ```cpp #include <wx/wx.h> class MyApp : public wxApp { public: virtual bool OnInit(); }; class MyFrame : public wxFrame { public: MyFrame(const wxString& title) : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(400, 300)) { // 创建主 Panel(作为整个窗口的内容承载) wxPanel* mainPanel = new wxPanel(this); // 创建水平 Box Sizer wxBoxSizer* hSizer = new wxBoxSizer(wxHORIZONTAL); // 创建两个子 Panel 并添加到主布局中 wxPanel* leftPanel = new wxPanel(mainPanel); leftPanel->SetBackgroundColour(*wxLIGHT_GREY); wxPanel* rightPanel = new wxPanel(mainPanel); rightPanel->SetBackgroundColour(wxColour(255, 220, 220)); // 淡红色 // 添加按钮到左右 Panel 中 wxButton* btn1 = new wxButton(leftPanel, wxID_ANY, "左边按钮"); wxButton* btn2 = new wxButton(rightPanel, wxID_ANY, "右边按钮"); // 设置每个 Panel 的布局 wxBoxSizer* leftSizer = new wxBoxSizer(wxVERTICAL); leftSizer->Add(btn1, 0, wxALIGN_CENTER | wxALL, 10); leftPanel->SetSizer(leftSizer); wxBoxSizer* rightSizer = new wxBoxSizer(wxVERTICAL); rightSizer->Add(btn2, 0, wxALIGN_CENTER | wxALL, 10); rightPanel->SetSizer(rightSizer); // 将两个 Panel 添加到主布局中 hSizer->Add(leftPanel, 1, wxEXPAND | wxALL, 5); hSizer->Add(rightPanel, 1, wxEXPAND | wxALL, 5); mainPanel->SetSizer(hSizer); } }; bool MyApp::OnInit() { MyFrame* frame = new MyFrame("wxPanel 示例 - C++"); frame->Show(true); return true; } wxIMPLEMENT_APP(MyApp); ``` --- ## ✅ Python 实现代码(wxPython) ```python import wx class MyFrame(wx.Frame): def __init__(self, *args, **kw): super(MyFrame, self).__init__(*kw) # 主 Panel main_panel = wx.Panel(self) # 水平布局 h_sizer = wx.BoxSizer(wx.HORIZONTAL) # 左边 Panel left_panel = wx.Panel(main_panel) left_panel.SetBackgroundColour(wx.Colour(211, 211, 211)) # 浅灰色 btn1 = wx.Button(left_panel, label="左边按钮") left_sizer = wx.BoxSizer(wx.VERTICAL) left_sizer.Add(btn1, 0, wx.ALIGN_CENTER | wx.ALL, 10) left_panel.SetSizer(left_sizer) # 右边 Panel right_panel = wx.Panel(main_panel) right_panel.SetBackgroundColour(wx.Colour(255, 220, 220)) # 淡红色 btn2 = wx.Button(right_panel, label="右边按钮") right_sizer = wx.BoxSizer(wx.VERTICAL) right_sizer.Add(btn2, 0, wx.ALIGN_CENTER | wx.ALL, 10) right_panel.SetSizer(right_sizer) # 添加到主布局 h_sizer.Add(left_panel, 1, wx.EXPAND | wx.ALL, 5) h_sizer.Add(right_panel, 1, wx.EXPAND | wx.ALL, 5) main_panel.SetSizer(h_sizer) self.SetTitle("wxPanel 示例 - Python") self.SetSize((400, 300)) self.Centre() class MyApp(wx.App): def OnInit(self): frame = MyFrame(None) frame.Show(True) return True if __name__ == '__main__': app = MyApp(False) app.MainLoop() ``` --- ## 🧩 控件常用样式说明(C++ / wxWidgets) | 样式名称 | 含义说明 | |----------------------|--------------------------------------------------------| | `wxTAB_TRAVERSAL` | 允许 Tab 键切换焦点 | | `wxFULL_REPAINT_ON_RESIZE` | 窗口大小变化时重绘全部内容 | > ⚠️ 注意:Python 中传入方式为 `style=wx.TAB_TRAVERSAL` 等。 --- ## 📌 主要功能与方法 | 方法名 | 描述 | |---------------------------|--------------------------------------------------------------| | `SetBackgroundColour(col)` | 设置背景颜色 | | `SetForegroundColour(col)` | 设置前景颜色(文本颜色) | | `SetFont(font)` | 设置字体 | | `GetParent()` | 获取父控件 | | `SetSizer(sizer)` | 设置布局管理器 | | `Refresh()` | 刷新面板内容(触发重绘) | | `Update()` | 强制立即更新界面 | --- ## 🎨 自定义绘制示例(C++) ```cpp class CustomPanel : public wxPanel { public: CustomPanel(wxWindow* parent) : wxPanel(parent) { Bind(wxEVT_PAINT, &CustomPanel::OnPaint, this); } private: void OnPaint(wxPaintEvent& event) { wxPaintDC dc(this); dc.SetBrush(*wxGREEN_BRUSH); dc.DrawCircle(GetSize().GetWidth() / 2, GetSize().GetHeight() / 2, 50); } }; ``` --- ## 📌 总结 | 特性 | 描述 | |---------------------|--------------------------------------------------------------| | 控件名称 | `wxPanel` | | 功能 | 提供控件容器功能,支持布局管理和视觉分区 | | 支持平台 | Windows / Linux / macOS | | 推荐用途 | 分组控件、布局管理、自定义界面绘制 | | 开发建议 | 配合 `wxSizer` 使用;合理使用背景色区分功能区域;避免过度嵌套 | --- 📌 **扩展功能建议:** - 使用 `wxScrolled<wxPanel>` 实现滚动面板 - 在 `wxPanel` 上绘制图形或实现动画效果 - 作为对话框、工具栏、状态栏的容器使用 - 结合 `wxNotebook` 或 `wxSplitterWindow` 构建复杂布局 - 替代 `wxWindow` 用于需要布局支持的场合 请根据上面的内容,实现扩展功能,要求,C++和PYTHON双语言支持,并对每一行代码都进行中文注解
最新发布
07-10
<think>我们将在上一节的基础上,为wxPanel添加扩展功能,包括自定义绘制和滚动面板的实现。 扩展功能1:自定义绘制面板(在面板上绘制图形) 扩展功能2:实现一个可滚动的面板(使用wxScrolledWindow) 注意:由于wxScrolledWindow在wxWidgets中是wxPanel的子类,在wxPython中通常使用wx.ScrolledWindow(等同于wxScrolled<wxPanel>) 我们将分别用C++和Python实现这两个扩展功能。 扩展功能1:自定义绘制 在自定义面板上绘制一个圆形,并响应窗口大小变化(圆形始终居中) 扩展功能2:可滚动面板 创建一个内容区域超出可见区域的面板,并支持滚动条。 我们将创建两个示例,分别展示这两个功能。 由于代码较长,我们将分开展示,但为了符合要求,我们将在一个回答中提供两种语言的实现。 注意:在C++中,自定义绘制需要处理EVT_PAINT事件,在Python中同样如此。 下面分别给出C++和Python的代码实现,并对每一行进行中文注解。</think># wxPanel 扩展功能实现:自定义绘制与滚动面板 下面我将实现两个扩展功能:自定义绘制面板和滚动面板,同时提供 C++ 和 Python 双语言支持,并对每一行代码进行详细注解。 ## 功能一:自定义绘制面板(带交互) ### C++ 实现 ```cpp #include <wx/wx.h> // 自定义面板类,支持绘制和点击交互 class CustomPanel : public wxPanel { public: CustomPanel(wxWindow* parent) : wxPanel(parent) { // 绑定绘制事件 Bind(wxEVT_PAINT, &CustomPanel::OnPaint, this); // 绑定鼠标点击事件 Bind(wxEVT_LEFT_DOWN, &CustomPanel::OnMouseClick, this); // 绑定鼠标移动事件 Bind(wxEVT_MOTION, &CustomPanel::OnMouseMove, this); // 初始化绘制位置 circlePos = wxPoint(100, 100); } private: wxPoint circlePos; // 圆形中心位置 // 绘制事件处理函数 void OnPaint(wxPaintEvent& event) { wxPaintDC dc(this); // 创建绘制设备上下文 // 设置背景色 dc.SetBackground(*wxWHITE_BRUSH); dc.Clear(); // 绘制标题文本 dc.SetFont(wxFont(14, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD)); dc.SetTextForeground(*wxBLUE); dc.DrawText("自定义绘制面板 (C++)", 10, 10); // 绘制圆形 dc.SetBrush(*wxGREEN_BRUSH); dc.SetPen(wxPen(*wxBLACK, 2)); dc.DrawCircle(circlePos, 50); // 绘制坐标文本 dc.SetTextForeground(*wxRED); dc.DrawText(wxString::Format("位置: (%d, %d)", circlePos.x, circlePos.y), circlePos.x - 40, circlePos.y + 60); } // 鼠标点击事件处理函数 void OnMouseClick(wxMouseEvent& event) { circlePos = event.GetPosition(); // 获取鼠标点击位置 Refresh(); // 刷新面板,触发重绘 event.Skip(); // 允许事件继续传播 } // 鼠标移动事件处理函数 void OnMouseMove(wxMouseEvent& event) { if (event.Dragging()) { // 检查是否在拖动(鼠标按下时移动) circlePos = event.GetPosition(); // 获取鼠标当前位置 Refresh(); // 刷新面板 } event.Skip(); // 允许事件继续传播 } }; // 主框架类 class MyFrame : public wxFrame { public: MyFrame(const wxString& title) : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(600, 400)) { // 创建主面板 wxPanel* mainPanel = new wxPanel(this); // 创建垂直布局管理器 wxBoxSizer* vSizer = new wxBoxSizer(wxVERTICAL); // 创建说明文本 wxStaticText* label = new wxStaticText(mainPanel, wxID_ANY, "点击或拖动鼠标移动圆形位置"); vSizer->Add(label, 0, wxALL | wxALIGN_CENTER, 10); // 创建自定义面板 CustomPanel* customPanel = new CustomPanel(mainPanel); customPanel->SetMinSize(wxSize(500, 300)); // 设置最小尺寸 // 添加到布局 vSizer->Add(customPanel, 1, wxEXPAND | wxALL, 10); // 设置主面板布局 mainPanel->SetSizer(vSizer); } }; // 应用程序类 class MyApp : public wxApp { public: virtual bool OnInit() { MyFrame* frame = new MyFrame("自定义绘制面板 - C++"); frame->Show(true); return true; } }; wxIMPLEMENT_APP(MyApp); ``` ### Python 实现 ```python import wx class CustomPanel(wx.Panel): def __init__(self, parent): super(CustomPanel, self).__init__(parent) # 初始化圆形位置 self.circlePos = wx.Point(100, 100) # 绑定事件处理函数 self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseClick) self.Bind(wx.EVT_MOTION, self.OnMouseMove) def OnPaint(self, event): dc = wx.PaintDC(self) # 创建绘制设备上下文 # 设置背景色 dc.SetBackground(wx.Brush(wx.Colour(255, 255, 255))) dc.Clear() # 绘制标题文本 dc.SetFont(wx.Font(14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) dc.SetTextForeground(wx.Colour(0, 0, 255)) dc.DrawText("自定义绘制面板 (Python)", 10, 10) # 绘制圆形 dc.SetBrush(wx.Brush(wx.Colour(0, 255, 0))) dc.SetPen(wx.Pen(wx.Colour(0, 0, 0), 2)) dc.DrawCircle(self.circlePos.x, self.circlePos.y, 50) # 绘制坐标文本 dc.SetTextForeground(wx.Colour(255, 0, 0)) dc.DrawText(f"位置: ({self.circlePos.x}, {self.circlePos.y})", self.circlePos.x - 40, self.circlePos.y + 60) def OnMouseClick(self, event): self.circlePos = event.GetPosition() # 获取鼠标点击位置 self.Refresh() # 刷新面板 event.Skip() # 允许事件继续传播 def OnMouseMove(self, event): if event.Dragging(): # 检查是否在拖动(鼠标按下时移动) self.circlePos = event.GetPosition() # 获取鼠标当前位置 self.Refresh() # 刷新面板 event.Skip() # 允许事件继续传播 class MyFrame(wx.Frame): def __init__(self, parent): super(MyFrame, self).__init__(parent, title="自定义绘制面板 - Python", size=(600, 400)) # 创建主面板 main_panel = wx.Panel(self) # 创建垂直布局管理器 v_sizer = wx.BoxSizer(wx.VERTICAL) # 创建说明文本 label = wx.StaticText(main_panel, label="点击或拖动鼠标移动圆形位置") v_sizer.Add(label, 0, wx.ALL | wx.ALIGN_CENTER, 10) # 创建自定义面板 custom_panel = CustomPanel(main_panel) custom_panel.SetMinSize((500, 300)) # 设置最小尺寸 # 添加到布局 v_sizer.Add(custom_panel, 1, wx.EXPAND | wx.ALL, 10) # 设置主面板布局 main_panel.SetSizer(v_sizer) self.Centre() class MyApp(wx.App): def OnInit(self): frame = MyFrame(None) frame.Show() return True if __name__ == "__main__": app = MyApp() app.MainLoop() ``` ## 功能二:可滚动面板 ### C++ 实现 ```cpp #include <wx/wx.h> #include <wx/scrolwin.h> // 可滚动面板类 class ScrollablePanel : public wxScrolledWindow { public: ScrollablePanel(wxWindow* parent) : wxScrolledWindow(parent, wxID_ANY) { // 设置滚动速率 SetScrollRate(10, 10); // 创建垂直布局管理器 wxBoxSizer* vSizer = new wxBoxSizer(wxVERTICAL); // 添加标题 wxStaticText* title = new wxStaticText(this, wxID_ANY, "可滚动面板 (C++)", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER); title->SetFont(wxFont(18, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD)); vSizer->Add(title, 0, wxALL | wxEXPAND, 20); // 添加多个内容面板 for (int i = 1; i <= 20; i++) { wxPanel* itemPanel = new wxPanel(this); itemPanel->SetBackgroundColour(wxColour(200, 230, 255 - i * 5)); // 渐变色 wxBoxSizer* hSizer = new wxBoxSizer(wxHORIZONTAL); // 添加序号标签 wxStaticText* numLabel = new wxStaticText(itemPanel, wxID_ANY, wxString::Format("项目 %d", i)); numLabel->SetFont(wxFont(14, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD)); // 添加描述文本 wxStaticText* descLabel = new wxStaticText(itemPanel, wxID_ANY, "这是可滚动面板中的一个项目,当内容超出可视区域时会出现滚动条"); // 添加到布局 hSizer->Add(numLabel, 0, wxALL | wxALIGN_CENTER_VERTICAL, 10); hSizer->Add(descLabel, 1, wxALL | wxALIGN_CENTER_VERTICAL, 10); itemPanel->SetSizer(hSizer); vSizer->Add(itemPanel, 0, wxALL | wxEXPAND, 5); } // 设置滚动窗口的尺寸 SetSizer(vSizer); FitInside(); // 让滚动区域适应内容 } }; // 主框架类 class MyFrame : public wxFrame { public: MyFrame(const wxString& title) : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(500, 400)) { // 创建可滚动面板 ScrollablePanel* scrollPanel = new ScrollablePanel(this); } }; // 应用程序类 class MyApp : public wxApp { public: virtual bool OnInit() { MyFrame* frame = new MyFrame("可滚动面板 - C++"); frame->Show(true); return true; } }; wxIMPLEMENT_APP(MyApp); ``` ### Python 实现 ```python import wx class ScrollablePanel(wx.ScrolledWindow): def __init__(self, parent): super(ScrollablePanel, self).__init__(parent) # 设置滚动速率 self.SetScrollRate(10, 10) # 创建垂直布局管理器 v_sizer = wx.BoxSizer(wx.VERTICAL) # 添加标题 title = wx.StaticText(self, label="可滚动面板 (Python)", style=wx.ALIGN_CENTER) title_font = wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD) title.SetFont(title_font) v_sizer.Add(title, 0, wx.ALL | wx.EXPAND, 20) # 添加多个内容面板 for i in range(1, 21): item_panel = wx.Panel(self) # 创建渐变色背景 color = wx.Colour(200, 230, 255 - i * 5) item_panel.SetBackgroundColour(color) h_sizer = wx.BoxSizer(wx.HORIZONTAL) # 添加序号标签 num_label = wx.StaticText(item_panel, label=f"项目 {i}") num_font = wx.Font(14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD) num_label.SetFont(num_font) # 添加描述文本 desc_label = wx.StaticText(item_panel, label="这是可滚动面板中的一个项目,当内容超出可视区域时会出现滚动条") # 添加到布局 h_sizer.Add(num_label, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 10) h_sizer.Add(desc_label, 1, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 10) item_panel.SetSizer(h_sizer) v_sizer.Add(item_panel, 0, wx.ALL | wx.EXPAND, 5) # 设置滚动窗口的尺寸 self.SetSizer(v_sizer) self.FitInside() # 让滚动区域适应内容 class MyFrame(wx.Frame): def __init__(self, parent): super(MyFrame, self).__init__(parent, title="可滚动面板 - Python", size=(500, 400)) # 创建可滚动面板 scroll_panel = ScrollablePanel(self) self.Centre() class MyApp(wx.App): def OnInit(self): frame = MyFrame(None) frame.Show() return True if __name__ == "__main__": app = MyApp() app.MainLoop() ``` ## 功能对比说明 | 功能特性 | 自定义绘制面板 | 可滚动面板 | |------------------|---------------------------------------------|-------------------------------------------| | **主要用途** | 创建自定义图形界面、实现特殊视觉效果 | 显示超出可视区域的内容 | | **核心技术** | 处理 `wxEVT_PAINT` 事件进行绘制 | 使用 `wxScrolledWindow` 提供滚动功能 | | **交互支持** | 支持鼠标点击、拖动等交互操作 | 自动支持滚动条交互 | | **性能考虑** | 需要优化绘制代码避免频繁刷新 | 适合显示大量内容,滚动时按需渲染 | | **适用场景** | 图表、游戏界面、自定义控件、数据可视化 | 长列表、文档查看器、配置面板、日志显示 | | **布局管理** | 通常使用绝对定位 | 配合 sizer 布局管理器使用 | ## 开发建议 1. **自定义绘制优化**: - 使用双缓冲技术避免闪烁:`wxBufferedPaintDC` - 只重绘需要更新的区域:`RefreshRect()` - 避免在绘制事件中进行复杂计算 2. **滚动面板最佳实践**: - 使用 `FitInside()` 而非 `Fit()` 确保滚动区域正确计算 - 对于大量内容,考虑虚拟滚动技术 - 设置合适的滚动步长 (`SetScrollRate()`) 3. **跨平台注意事项**: - 在 macOS 上,滚动条行为可能与其他平台不同 - 高DPI屏幕需要额外处理缩放 - 不同平台默认字体大小可能影响布局
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值