纯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差不多,可以设置大写留余地。

下面直接上完整代码,可以运行的,只实现了拖动滚动块事件,其他事件自己补充吧

[cpp] view plain copy

    1. #include <windows.h>
    2. #define  IDC_CANVAS                  200
    3. HWND hwnd_screen = NULL;//屏幕句柄,这里的屏幕既是我们创建的顶级窗口
    4. HWND hwnd_canvas = NULL;//画布句柄
    5. HINSTANCE   Ghinstance = NULL;//程序实例
    6. //注意:以下提到的“屏幕”指的都是我们创建的模拟屏幕,也就是顶级窗口,而不是我们计算机的屏幕
    7. int         canvas_width        = 2000;//画布长度
    8. int         canvas_height       = 1500;//画布宽度
    9. int         screen_width        = 0;//屏幕长度
    10. int         screen_height       = 0;//屏幕宽度
    11. int         position_width      = 0;//当前位置的横坐标
    12. int         position_height     = 0;//当前位置的纵坐标
    13. int         hb_pos              = 0;//竖直方向滚动条当前位置
    14. int         vb_pos              = 0;//水平方向滚动条当前位置
    15. LRESULT CALLBACK ScreenProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam);//屏幕事件处理函数
    16. LRESULT CALLBACK CanvasProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam);//画布事件处理函数
    17. //入口函数
    18. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    19. //========================================创建屏幕begin==================================================
    20. WNDCLASSEX wc;
    21. MSG Msg;
    22. memset(&wc,0,sizeof(wc));
    23. wc.cbSize        = sizeof(WNDCLASSEX);
    24. wc.lpfnWndProc   = ScreenProc;
    25. wc.hInstance     = hInstance;
    26. wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    27. wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    28. wc.lpszClassName = "WindowClass";
    29. wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    30. if(!RegisterClassEx(&wc)) {
    31. MessageBox(NULL, "Window Registration Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
    32. return 0;
    33. }
    34. //程序实例和屏幕句柄放到全局变量里
    35. Ghinstance = hInstance;
    36. hwnd_screen = CreateWindowEx(WS_EX_CLIENTEDGE,"WindowClass","Caption",WS_VISIBLE|WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
    37. CW_USEDEFAULT,
    38. CW_USEDEFAULT,
    39. 800,
    40. 600,
    41. NULL,NULL,hInstance,NULL);
    42. if(hwnd_screen == NULL) {
    43. MessageBox(NULL, "Screen Creation Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
    44. return 0;
    45. }
    46. //========================================创建屏幕end==================================================
    47. //你也可以把创建画布的过程放到屏幕的WM_CREATE事件中,放这里是使读者思路能清晰些
    48. //========================================创建画布begin==================================================
    49. wc;
    50. memset(&wc,0,sizeof(wc));
    51. wc.cbSize        = sizeof(WNDCLASSEX);
    52. wc.lpszClassName = "Canvas";
    53. wc.lpfnWndProc   = CanvasProc;
    54. wc.hInstance     = Ghinstance;//这里可以直接使用全局变量了
    55. wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    56. wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
    57. if(!RegisterClassEx(&wc)) {
    58. MessageBox(NULL, "Canvas Registration Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
    59. return 0;
    60. }
    61. hwnd_canvas= CreateWindow(
    62. "Canvas",
    63. "",
    64. WS_CHILD | WS_VISIBLE | WS_BORDER,
    65. 0, 0, canvas_width, canvas_height,
    66. hwnd_screen,//这里可以直接使用全局变量了,注意,如果是放屏幕的WM_CREATE里面,这时候是还不能使用这个全局变量的,WM_CREATE事件结束后CreateWindow方法才会返回创建窗口的句柄
    67. (HMENU)IDC_CANVAS,
    68. Ghinstance,//这里可以直接使用全局变量了
    69. 0
    70. );
    71. if(hwnd_canvas == NULL) {
    72. MessageBox(NULL, "Canvas Creation Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
    73. return 0;
    74. }
    75. //========================================创建画布end==================================================
    76. //该显示的显示
    77. ShowWindow(hwnd_screen, nCmdShow);
    78. UpdateWindow(hwnd_screen);
    79. //该显示的显示
    80. ShowWindow(hwnd_canvas, SW_SHOW);
    81. UpdateWindow(hwnd_canvas);
    82. //消息循环
    83. while(GetMessage(&Msg, NULL, 0, 0) > 0) {
    84. TranslateMessage(&Msg);
    85. DispatchMessage(&Msg);
    86. }
    87. return Msg.wParam;
    88. }
    89. //屏幕的事件
    90. LRESULT CALLBACK ScreenProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
    91. //只需要处理WM_SIZE、WM_HSCROLL、WM_VSCROLL三个消息
    92. switch(Message) {
    93. //窗口大小改变时,更新全局变量中的屏幕大小,更新滚动条上滚动块的位置
    94. case WM_SIZE: {
    95. //更新屏幕大小begin-----------------------------
    96. screen_width = LOWORD (lParam);
    97. screen_height = HIWORD (lParam);
    98. //更新屏幕大小end-----------------------------
    99. //更新滚动条上滚动块的位置begin----------------------
    100. hb_pos = position_width * 100 / (canvas_width - screen_width);//根据恒等式1
    101. vb_pos = position_height * 100 / (canvas_height - screen_height);
    102. SCROLLINFO  si;
    103. si.cbSize=sizeof(SCROLLINFO);
    104. si.fMask=SIF_POS;
    105. si.nPos = vb_pos;
    106. SetScrollInfo(hwnd_screen,SB_VERT,&si,true);
    107. si.nPos = hb_pos;
    108. SetScrollInfo(hwnd_screen,SB_HORZ,&si,true);
    109. //更新滚动条上滚动块的位置end----------------------
    110. //其实还应该更新滚动条上滚动块的长度,这里先忽略吧
    111. //int hb_length = GValue::s_width * (GValue::s_width - 40) / GValue::c_width;//根据恒等式2
    112. //int vb_length = GValue::s_height * (GValue::s_height - 40) / GValue::c_height;
    113. break;
    114. }
    115. //水平方向滚动条事件
    116. case WM_HSCROLL : {
    117. SCROLLINFO  si;
    118. si.cbSize=sizeof(SCROLLINFO);
    119. si.fMask=SIF_ALL;
    120. GetScrollInfo(hwnd_screen,SB_HORZ,&si);//先拿滚动条信息
    121. switch(LOWORD(wParam)){//这里只处理按下滚动条拖动的事件,其他滚动条事件自己实现吧
    122. //分析可知按住滚动条拖动过程中,需要修改当前位置、然后基于当前位置移动画布,最后修改滚动条位置(你不修改的话视觉效果上会弹回去的)、
    123. case SB_THUMBTRACK: {
    124. position_width = si.nTrackPos * (canvas_width - screen_width) / 100;//更改当前位置
    125. MoveWindow(hwnd_canvas, 0 - position_width, 0 - position_height, canvas_width, canvas_height, true);//移动画布
    126. si.nPos=si.nTrackPos;
    127. break;
    128. }
    129. //TODO 滚动条的其他事件
    130. default: {
    131. break;
    132. }
    133. }
    134. //回写滚动条滚动块的位置,时视觉上正常
    135. si.fMask=SIF_POS;
    136. SetScrollInfo(hwnd_screen, SB_HORZ, &si, true);
    137. break;
    138. }
    139. //竖直方向滚动条事件,与上面相似不解释了
    140. case WM_VSCROLL : {
    141. SCROLLINFO  si;
    142. si.cbSize=sizeof(SCROLLINFO);
    143. si.fMask=SIF_ALL;
    144. GetScrollInfo(hwnd_screen, SB_VERT, &si);
    145. switch(LOWORD(wParam)){
    146. case SB_THUMBTRACK: {
    147. position_height = si.nTrackPos * (canvas_height - screen_height) / 100;
    148. MoveWindow(hwnd_canvas, 0 - position_width, 0 - position_height, canvas_width, canvas_height, true);
    149. si.nPos=si.nTrackPos;
    150. break;
    151. }
    152. default: {
    153. break;
    154. }
    155. }
    156. si.fMask=SIF_POS;
    157. SetScrollInfo(hwnd_screen, SB_VERT, &si, true);
    158. break;
    159. }
    160. //鼠标滚轮
    161. /*      case WM_MOUSEWHEEL : {
    162. //向下
    163. if(HIWORD(wParam) < 0) {
    164. vb_pos = vb_pos + 10;
    165. if(vb_pos > 100) {
    166. vb_pos = 0;
    167. }
    168. } else {
    169. vb_pos = vb_pos - 10;
    170. if(vb_pos < 0) {
    171. vb_pos = 0;
    172. }
    173. }
    174. break;
    175. }
    176. */
    177. case WM_CLOSE: {
    178. DestroyWindow(hwnd);
    179. break;
    180. }
    181. case WM_DESTROY: {
    182. PostQuitMessage(0);
    183. break;
    184. }
    185. default:
    186. return DefWindowProc(hwnd, Message, wParam, lParam);
    187. }
    188. return 0;
    189. }
    190. //窗口的事件
    191. LRESULT CALLBACK CanvasProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
    192. switch(Message) {
    193. //从画布左上角到右下角画一条线,以便观察滚动效果
    194. case WM_PAINT: {
    195. PAINTSTRUCT ps;
    196. HDC hdc;
    197. RECT rc;
    198. GetClientRect(hwnd_canvas, &rc);
    199. hdc = BeginPaint(hwnd_canvas, &ps);
    200. MoveToEx(hdc, 0 , 0 , NULL);
    201. LineTo(hdc, rc.right, rc.bottom);
    202. EndPaint(hwnd_canvas, &ps);
    203. break;
    204. }
    205. case WM_CLOSE: {
    206. DestroyWindow(hwnd);
    207. break;
    208. }
    209. case WM_DESTROY: {
    210. PostQuitMessage(0);
    211. break;
    212. }
    213. default:
    214. return DefWindowProc(hwnd, Message, wParam, lParam);
    215. }
    216. }
时间: 2024-10-16 21:57:39

纯c++实现之滚动窗口的相关文章

Delphi TScrollBar 用于滚动窗口、组件内容

滚动条组件(TScrollBar)此组件是一个Windows滚动条,用于滚动窗口.组件内容.许多控制有滚动条属性,它们把滚动条作为自己的一部分,对于没有完整滚动条的控制,TScrollBar组件提供了一个附加的功能,运用它可以使某些控制的内容易于操作. 1.TScrollBar组件的典型用法 一般情况下,滚动条是自动加入的,例如前面讲的列表框,当项目不能完全显示时,列表框将自动加上滚动条.当用户操作滚动条时,列表自动滚动. 如果想自己操纵窗口滚动,就要用到TScrollBar组件,当用户在滚动条

纯代码实现横向滚动的UIScrollView

// 纯代码实现横向滚动的UIScrollView //  NeedListViewController.m // // //  Copyright © 2016年  All rights reserved. // #import "CFNeedListViewController.h" #import "CFWaitingViewController.h" #import "CFRespondedViewController.h" #impor

java GUI编程(swing)之四swing下拉框,列表框,滚动窗口

下拉框(JComboBox) 列表框(JList) 滚动窗口(JScrollPane) package gui; import java.awt.GridLayout; import javax.swing.*; /** * 下拉框,列表框,窗口滚动 * Created by admin on 2017/7/9. */ public class Scroll extends JFrame{ // 定义需要用到的组件 private JList jList; private JComboBox j

PB做大屏显示滚动窗口 [转载]

前段时间接到一个同事的求助 一个客户需求做门诊已完成报告通知取单的大屏显示界面 百度了一下,其实很简单 实现方法如下 1.用要显示数据的sql语句做成数据窗口(datawindow): 2.在窗体(window)中嵌入window: 3.在窗体的open事件中加入timer事件: 4.在timer事件中对datawindow进行操作,用datawindow的scrolltorow方法滚动到对应行: 5.当滚动到对应行大于等于datawindow的rowcount是滚动行重新回到第一行: //窗口

使用GDI+在winform中绘制滚动窗口教程

在winform中绘制图形,可以使用gdi+来完成.当绘制的图形大于目前窗口大小时,就需要滚动条来帮忙显示. 设置属性:Form.AutoScrollMinSize为要显示内容的大小. 在OnPaint方法中,利用this.AutoScrollPosition获取原点坐标相对于当前顶点坐标的矢量,进行矢量相减后,得到当前绘制图形的坐标. 还有更多相关编程语言教程可以登录e良师益友网学习.

运用onscroll事件//滚动窗口滚动条时触发

<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title></title> <style> body{ margin: 0; padding: 0; position:relative; } header{ width:100%; height: 50px; background: #f00; } nav{ width: 100%; heigh

JS纯生实现无缝滚动轮播图

1.定时器加上以后需要进入一次才能引用,所以在上面提前调用一次定时器: 2.当在实现下标小按钮的时候一定要给第三部的num赋值: 3.切记谁做动画谁加定位

史上最详细 纯CSS打造3D文本滚动

昨天看见了一篇文章关于用纯CSS实现文本滚动,在这里跟大家分享一下. 首先把效果图贴给大家 根据效果图我们很容易发现肯定是要用到3D转换的,如果对这个还不是很了解的可以先看看下面的文章 http://www.zhangxinxu.com/wordpress/2012/09/css3-3d-transform-perspective-animate-transition/comment-page-1/ http://www.w3cplus.com/blog/tags/95.html 那么首先我们就

鼠标滚动,导航置顶.纯css3的position: sticky;

position: sticky; 这东西来自css3,并且瞬间就完成了置顶的效果. <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <style> .a{ //定位头部置顶效果 top: 0; position: sticky; } .b{ //当纯的给个滚