GUI

处理windows上的窗口尺寸变化

什么时候调用setMode?

  • 初始化阶段的init_video()。
  • 要修改朝向。竖屏、横屏切换。

 

这里说的窗口尺寸变化不包括修改朝向,因而发生后,不会调用setMode。这里要考虑的主要是两种情况。

  1. 单击左上角的“最大/恢复”按钮。
  2. 拉着窗口边框,改变尺寸。

以单击左上角的“最大/恢复”按钮为例,看是怎么处理的。

  1. (SDL)WIN_WIndowProc。收到WM_WINDOWPOSCHANGED消息,调用SDL_OnWindowResized,执行向队列放入SDL_WINDOWEVENT_SIZE_CHANGED事件。
  2. (SDL)WIN_WIndowProc。收到WM_SIZE(wParam:SIZE_MAXIMIZED)消息。不是向队列放一个新事件,而是调用app挂接的sdl_apphandlers.window_event_handler,后者对应app的handle_window_event。
  3. (app)base_instance::handle_window_event。发现type是SDL_WINDOWEVENT_MAXIMIZED,preferences的maximized置为true。
  4. (app)events::pump。收到“event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED”,调用base_instance::handle_resize_screen。
  5. (app)handle_resize_screen。调用gui2::absolute_draw_all重画窗口,包括place各控件。

在WIN_WIndowProc消息序列上, 是先WM_WINDOWPOSCHANGED,然后SDL_WINDOWEVENT_MAXIMIZED。由于CHANGED是向队列加事件,MAXIMIZED是立即调用app的handle_window_event。在app看来,是先handle_window_event,然后handle_resize_screen。

在处理SIZE_CHANGED,先判断是否正处在最大化,如果是,不要保存x、y到preferences。避免在启动是最大化时,第一次回到常规,还是大窗口。

在最小化时,app会收到SDL_WINDOWEVENT_SIZE_CHANGED吗?——不会。从最小化恢复到常规时,也不会。也就说,这两种情况下,都不会调用app的base_instance::handle_resize_screen。

在base_instance::handle_resize_screen,会调用tdialog的resize_screen(),后者会调用虚函数app_resize_screen()。在某个tdialog,如果有预创建的texture/surface是和尺寸密切相关,那重载app_resiz_screen,内中释放掉这些已存在的,然后重新创建。

对“拉着窗口边框,改变尺寸”,它没有2、3步骤。

 

场景时

在场景,总体遵循上面逻辑,在第5步会有不同。而且在那里,会分出两种处理方法。

  1. 和dialog一样,使用重载tdialog::app_resize_screen方法。
  2. 不使用重载tdialog::app_resize_screen。handle_resize_screen会调用preferences::::set_resolution,在那里把display::require_change_resolution置为true。event::pump发现require_change_resolution是true,调用disp->change_resolution()。过程中,会销毁、并创建新的tdialog,因而不推荐使用。为什么会有这种方法?——有时改变的不仅仅尺寸,而是屏幕分辨率,像要求画质较高的游戏。
<launcher>/health_display.hpp
------
bool use_app_resize_screen() const override { return true; }

要让场景时使用app_resize_screen方法,需在xxx_display重载use_app_resize_screen,并返回true。这方法时,app_resize_screen一般用着以下逻辑。

<launcher>/health_controller.cpp
------
void health_controller::app_resize_screen()
{
	// 手动重布局窗口
	window_->layout();
	// 因为重布局了,得到_bit_map控件的矩形:main_map_rect_
	gui_->update_main_map_rect();
	// 重画大地图背景图像。如果大地图比main_map_rect_小,会露出部分背景图像。
	gui_->enable_redraw_background();
	// 窗口尺寸变了,为美观,得修正display中的xpos_、ypos_
	gui_->fix_xpos_ypos();

	// 以下是各窗口私有逻辑了。
	make_sure_map();

	VALIDATE(curr_chartsel_ != nposm, null_str);
	refresh_chart_by_sel(curr_chartsel_);

	if (watermark_halo_ != halo::NO_HALO) {
		did_watermark_text_changed(*dlg_->watermark_widget().text_box());
	}
}

全部评论: 0

    写评论: