纯c++实现之滚动窗口
别在MFC了,先分析下,上图
我们以左上角为坐标原点,用position_width和position_height来保存当前显示坐标。
根据msdn说明,滚动条默认情况下的值在0~100之间。
根据图可以知道positon_width的活动范围是0到canvas_width-screen-width,另一边类似。
所以有恒等式1:position_width/(canvas_width-screen_width) = hb_pos/100,其中hb_pos是水平方向滚动条当前值。
滚动块长度公式2:screen_width/canvas_width = 滚动块长度/滚动条可滚动区域长度,滚动条可滚动区域长度大概是screen_width-40差不多,可以设置大写留余地。
下面直接上完整代码,可以运行的,只实现了拖动滚动块事件,其他事件自己补充吧
- #include <windows.h>
- #define IDC_CANVAS 200
- HWND hwnd_screen = NULL;//屏幕句柄,这里的屏幕既是我们创建的顶级窗口
- HWND hwnd_canvas = NULL;//画布句柄
- HINSTANCE Ghinstance = NULL;//程序实例
- //注意:以下提到的“屏幕”指的都是我们创建的模拟屏幕,也就是顶级窗口,而不是我们计算机的屏幕
- int canvas_width = 2000;//画布长度
- int canvas_height = 1500;//画布宽度
- int screen_width = 0;//屏幕长度
- int screen_height = 0;//屏幕宽度
- int position_width = 0;//当前位置的横坐标
- int position_height = 0;//当前位置的纵坐标
- int hb_pos = 0;//竖直方向滚动条当前位置
- int vb_pos = 0;//水平方向滚动条当前位置
- LRESULT CALLBACK ScreenProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam);//屏幕事件处理函数
- LRESULT CALLBACK CanvasProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam);//画布事件处理函数
- //入口函数
- int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
- //========================================创建屏幕begin==================================================
- WNDCLASSEX wc;
- MSG Msg;
- memset(&wc,0,sizeof(wc));
- wc.cbSize = sizeof(WNDCLASSEX);
- wc.lpfnWndProc = ScreenProc;
- wc.hInstance = hInstance;
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
- wc.lpszClassName = "WindowClass";
- wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
- if(!RegisterClassEx(&wc)) {
- MessageBox(NULL, "Window Registration Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
- return 0;
- }
- //程序实例和屏幕句柄放到全局变量里
- Ghinstance = hInstance;
- hwnd_screen = CreateWindowEx(WS_EX_CLIENTEDGE,"WindowClass","Caption",WS_VISIBLE|WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
- CW_USEDEFAULT,
- CW_USEDEFAULT,
- 800,
- 600,
- NULL,NULL,hInstance,NULL);
- if(hwnd_screen == NULL) {
- MessageBox(NULL, "Screen Creation Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
- return 0;
- }
- //========================================创建屏幕end==================================================
- //你也可以把创建画布的过程放到屏幕的WM_CREATE事件中,放这里是使读者思路能清晰些
- //========================================创建画布begin==================================================
- wc;
- memset(&wc,0,sizeof(wc));
- wc.cbSize = sizeof(WNDCLASSEX);
- wc.lpszClassName = "Canvas";
- wc.lpfnWndProc = CanvasProc;
- wc.hInstance = Ghinstance;//这里可以直接使用全局变量了
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
- if(!RegisterClassEx(&wc)) {
- MessageBox(NULL, "Canvas Registration Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
- return 0;
- }
- hwnd_canvas= CreateWindow(
- "Canvas",
- "",
- WS_CHILD | WS_VISIBLE | WS_BORDER,
- 0, 0, canvas_width, canvas_height,
- hwnd_screen,//这里可以直接使用全局变量了,注意,如果是放屏幕的WM_CREATE里面,这时候是还不能使用这个全局变量的,WM_CREATE事件结束后CreateWindow方法才会返回创建窗口的句柄
- (HMENU)IDC_CANVAS,
- Ghinstance,//这里可以直接使用全局变量了
- 0
- );
- if(hwnd_canvas == NULL) {
- MessageBox(NULL, "Canvas Creation Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
- return 0;
- }
- //========================================创建画布end==================================================
- //该显示的显示
- ShowWindow(hwnd_screen, nCmdShow);
- UpdateWindow(hwnd_screen);
- //该显示的显示
- ShowWindow(hwnd_canvas, SW_SHOW);
- UpdateWindow(hwnd_canvas);
- //消息循环
- while(GetMessage(&Msg, NULL, 0, 0) > 0) {
- TranslateMessage(&Msg);
- DispatchMessage(&Msg);
- }
- return Msg.wParam;
- }
- //屏幕的事件
- LRESULT CALLBACK ScreenProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
- //只需要处理WM_SIZE、WM_HSCROLL、WM_VSCROLL三个消息
- switch(Message) {
- //窗口大小改变时,更新全局变量中的屏幕大小,更新滚动条上滚动块的位置
- case WM_SIZE: {
- //更新屏幕大小begin-----------------------------
- screen_width = LOWORD (lParam);
- screen_height = HIWORD (lParam);
- //更新屏幕大小end-----------------------------
- //更新滚动条上滚动块的位置begin----------------------
- hb_pos = position_width * 100 / (canvas_width - screen_width);//根据恒等式1
- vb_pos = position_height * 100 / (canvas_height - screen_height);
- SCROLLINFO si;
- si.cbSize=sizeof(SCROLLINFO);
- si.fMask=SIF_POS;
- si.nPos = vb_pos;
- SetScrollInfo(hwnd_screen,SB_VERT,&si,true);
- si.nPos = hb_pos;
- SetScrollInfo(hwnd_screen,SB_HORZ,&si,true);
- //更新滚动条上滚动块的位置end----------------------
- //其实还应该更新滚动条上滚动块的长度,这里先忽略吧
- //int hb_length = GValue::s_width * (GValue::s_width - 40) / GValue::c_width;//根据恒等式2
- //int vb_length = GValue::s_height * (GValue::s_height - 40) / GValue::c_height;
- break;
- }
- //水平方向滚动条事件
- case WM_HSCROLL : {
- SCROLLINFO si;
- si.cbSize=sizeof(SCROLLINFO);
- si.fMask=SIF_ALL;
- GetScrollInfo(hwnd_screen,SB_HORZ,&si);//先拿滚动条信息
- switch(LOWORD(wParam)){//这里只处理按下滚动条拖动的事件,其他滚动条事件自己实现吧
- //分析可知按住滚动条拖动过程中,需要修改当前位置、然后基于当前位置移动画布,最后修改滚动条位置(你不修改的话视觉效果上会弹回去的)、
- case SB_THUMBTRACK: {
- position_width = si.nTrackPos * (canvas_width - screen_width) / 100;//更改当前位置
- MoveWindow(hwnd_canvas, 0 - position_width, 0 - position_height, canvas_width, canvas_height, true);//移动画布
- si.nPos=si.nTrackPos;
- break;
- }
- //TODO 滚动条的其他事件
- default: {
- break;
- }
- }
- //回写滚动条滚动块的位置,时视觉上正常
- si.fMask=SIF_POS;
- SetScrollInfo(hwnd_screen, SB_HORZ, &si, true);
- break;
- }
- //竖直方向滚动条事件,与上面相似不解释了
- case WM_VSCROLL : {
- SCROLLINFO si;
- si.cbSize=sizeof(SCROLLINFO);
- si.fMask=SIF_ALL;
- GetScrollInfo(hwnd_screen, SB_VERT, &si);
- switch(LOWORD(wParam)){
- case SB_THUMBTRACK: {
- position_height = si.nTrackPos * (canvas_height - screen_height) / 100;
- MoveWindow(hwnd_canvas, 0 - position_width, 0 - position_height, canvas_width, canvas_height, true);
- si.nPos=si.nTrackPos;
- break;
- }
- default: {
- break;
- }
- }
- si.fMask=SIF_POS;
- SetScrollInfo(hwnd_screen, SB_VERT, &si, true);
- break;
- }
- //鼠标滚轮
- /* case WM_MOUSEWHEEL : {
- //向下
- if(HIWORD(wParam) < 0) {
- vb_pos = vb_pos + 10;
- if(vb_pos > 100) {
- vb_pos = 0;
- }
- } else {
- vb_pos = vb_pos - 10;
- if(vb_pos < 0) {
- vb_pos = 0;
- }
- }
- break;
- }
- */
- case WM_CLOSE: {
- DestroyWindow(hwnd);
- break;
- }
- case WM_DESTROY: {
- PostQuitMessage(0);
- break;
- }
- default:
- return DefWindowProc(hwnd, Message, wParam, lParam);
- }
- return 0;
- }
- //窗口的事件
- LRESULT CALLBACK CanvasProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
- switch(Message) {
- //从画布左上角到右下角画一条线,以便观察滚动效果
- case WM_PAINT: {
- PAINTSTRUCT ps;
- HDC hdc;
- RECT rc;
- GetClientRect(hwnd_canvas, &rc);
- hdc = BeginPaint(hwnd_canvas, &ps);
- MoveToEx(hdc, 0 , 0 , NULL);
- LineTo(hdc, rc.right, rc.bottom);
- EndPaint(hwnd_canvas, &ps);
- break;
- }
- case WM_CLOSE: {
- DestroyWindow(hwnd);
- break;
- }
- case WM_DESTROY: {
- PostQuitMessage(0);
- break;
- }
- default:
- return DefWindowProc(hwnd, Message, wParam, lParam);
- }
- }
纯c++实现之滚动窗口的更多相关文章
- 李洪强iOS开发之后使用纯代码实现横向滚动的UIScrollView
李洪强iOS开发之后使用纯代码实现横向滚动的UIScrollView (VTmagic是一个实现左右滚动的控制器的框架,也可以实现此功能) 实现的效果: 01 - 创建四个控制器 02 - 定义需要 ...
- Delphi TScrollBar 用于滚动窗口、组件内容
滚动条组件(TScrollBar)此组件是一个Windows滚动条,用于滚动窗口.组件内容.许多控制有滚动条属性,它们把滚动条作为自己的一部分,对于没有完整滚动条的控制,TScrollBar组件提供了 ...
- Flink Streaming基于滚动窗口的事件时间分析
使用flink-1.9.0进行的测试,在不同的并行度下,Flink对事件时间的处理逻辑不同.包括1.1在并行度为1的本地模式分析和1.2在多并行度的本地模式分析两部分.通过理论结合源码进行验证,得到具 ...
- Qt 滚动窗口类
{ QScrollArea *scrollArea = new QScrollArea(this); scrollArea->setFrameStyle(); scrollArea->se ...
- 纯Js ——文字上下左右滚动
ScrollBaseJs.js var $$ = function (id) { return typeof id == 'string' ? document.getElementById(id) ...
- 使用纯 CSS 实现滚动阴影效果
开门见山,有这样一种非常常见的情况,对于一些可滚动的元素而言.通常在滚动的时候会给垂直于滚动的一侧添加一个阴影,用于表明当前有元素被滚动给该滚出了可视区域,类似这样: 可以看到,在滚动的过程中,会出现 ...
- JS平滑无缝滚动实现———实现首页广告自动滚动效果(附实例)
本文我们实现纯JS方式的滚动广告效果. 先show一下成品: 首先是网页样式: 1. #demo { 2. background: #FFF; 3. overflow:hidden; 4. borde ...
- Storm Windowing storm滑动窗口简介
Storm Windowing 简介 Storm可同时处理窗口内的所有tuple.窗口可以从时间或数量上来划分,由如下两个因素决定: 窗口的长度,可以是时间间隔或Tuple数量: 滑动间隔(slidi ...
- 【jQuery】scroll 滚动到顶部
Jquery 实现页面滚动到顶端 $(document).ready(function () { // 滚动窗口来判断按钮显示或隐藏 $(window).scroll(function () { // ...
随机推荐
- Linux 下WordPress FTP帐号解决办法
自己用Ubuntu搭建WordPress后在更换主题时提示需要输入FTP帐号和密码,解决办法主要是把WordPress主目录的权限所有者弄为Apache: 找到apache服务所使用的用户名和用户组 ...
- Andoid 利用ndk-stack定位崩溃代码
Android NDK自从版本R6开始, 提供了一个工具ndk-stack( 在目录{ndk_root}/中 ). 这个工具能自动分析dump下来的crash log, 将崩溃时的调用内存地址和c++ ...
- Java——IO(输入输出流)
* * 想要知道开发时用到哪些数据对象,只要通过四个明确即可: * 1.明确源,和目的: * 源: InputStream reader * 目的: OutPutStream Write ...
- C++命名空间<转>
熟练掌握C/C++语言,熟悉Windows开发平台,能熟练运用MFC自主编开发出一些应用程序: 熟练掌握SQL语句,对数据库有很好的认识,能熟练使用SQL Server2000软件: 熟练掌握JAVA ...
- (转)word2vec前世今生
word2vec 前世今生 2013年,Google开源了一款用于词向量计算的工具——word2vec,引起了工业界和学术界的关注.首先,word2vec可以在百万数量级的词典和上亿的数据集上进行高效 ...
- HTTPS-SSL/TSL与SNI的关系以及同IP多域名虚拟主机的SSL/TSL认证
早期的SSLv2根据经典的公钥基础设施PKI(Public Key Infrastructure)设计,它默认认为:一台服务器(或者说一个IP)只会提供一个服务,所以在SSL握手时,服务器端可以确信客 ...
- python模块结构和布局
用模块来合理的组织你的python代码是简单又自然的方法.下面介绍一种非常合理的布局: #(1)起始行(Unix) #(2)模块文档 #(3)模块导入 #(4)变量定义 #(5)类定义 #(6)函数定 ...
- timestamp 与 rowversion
联机丛书: timestamp timestamp 这种数据类型表现自动生成的二进制数,确保这些数在数据库中是唯一的.timestamp 一般用作给表行加版本戳的机制.存储大小为 8 字节. 注释 T ...
- 从扩展方法到匿名方法再到LINQ
1.首先我们应该知道什么是扩展方法: 扩展方法使您能够向现有类型“添加”方法,而无需创建新的派生类型.重新编译或以其他方式修改原始类型. 扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样 ...
- form表单回车提交问题,JS监听回车事件
我们有时候希望回车键敲在文本框(input element)里来提交表单(form),但有时候又不希望如此.比如搜索行为,希望输入完关键词之后直接按回车键立即提交表单,而有些复杂表单,可能要避免回车键 ...