改变窗口的外观和大小

From: http://blog.csdn.net/yoyobaibai/article/details/6044101


改变窗口的外观和大小需要在窗口创建以前改变。 所以我们可以在CMainFrame的 PreCreateWindow中改变CREATESTRUCT 结构体的值就行了。

 

E.G.

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)

改变窗口的大小 -> cs.cx = 300; cs.cy = 200;

 

改变窗口的显示位置坐标是 cs.x 和 cs.y

 

这里常用的一个函数是::GetSysMetrics(SM_CXSCREEN);

::GetSysMetrics(SM_CYSCREEN);

用来取得屏幕的大小。

 

要改变窗口标题栏的字符串:

   cs.lpszName = "Seven"; 会发现标题栏不会改变窗口的标题栏的上的字符串。

改变单文档应用程序的标题栏的字符串 参考MSDN  window styles/Frame-window styles 下面有一个Changing the styles of a window create by MFC./ The SDI Case

默认的情况是WS_OVERLAPPEDWINDOW and FWS_ADDTOTITLE styles

FWS_ADDTOTITLE is add the document title to the window’s caption.

去掉FWS_ADDTOTITLE 就可以更改窗口标题栏字符串。

 cs.style &= ~FWS_ADDTOTITLE;

cs.lpszName = "Seven";

 

 

如果我们需要改变背景, 画刷, 光标等等时候。

我们可以在:PreCreateWindow中创建窗口类, WNDCLASS wndClass;

把这个类里的值改变成自己想要的内容就可以了。

E.G.

wndClass.cbClsExtra = 0;

wndClass.cbWndExtra = 0;

wndClass.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH);

wndClass.hCursor = LoadCursor(NULL, IDC_WAIT);

wndClass.hIcon = LoadIcon(NULL, IDI_WARNING);

wndClass.hInstance = AfxGetInstanceHandle();

获取应用程序的实例句柄可用AfxGetInstanceHandle函数, 这个函数是一个全局的函数, 前面有一个AFX表示是一个应用程序框架类函数,哪里都可用。

wndClass.lpfnWndProc = ::DefWindowProc;

我们只是想要改变窗口的图标, 光标,不想改变条用过程所以用defWindowProc函数来处理。

因为在CWnd中也有一个defWindowProc函数,比全局的函数少一个参数 如果不加::的话调用就要报错。

wndClass.lpszMenuName = NULL;

创建菜单并不是在在设计窗口类的时候创建, 菜单的创建实在CStyleAPP::InitInstance函数中将菜单的标识传进去。

wndClass.style = CS_HREDRAW | CS_VREDRAW;

这里的style并不是窗口的类型而是窗口类的类型。

RegisterClass(&wndClass);

注册窗口类。

cs.lpszClass = "GL";

后来把我们刚刚设计好的类赋值个cs.lpszClass。

 

运行程序之后我们会发现只有图标改变了, cursor  和brush都没有改变。这是因为, 我们是在frame中改变的,在frame上边还覆盖一个子窗口类。所以我要改变这些需要把在子窗口的View类中PreCreateWindow中把类名复制。

E.g

在CStyleView中 cs.lpszClass = "GL";

就可以把我们刚刚的想要的类型来改变view中的窗口类型, 因为“GL”窗口类已经在CMainFrame框架类中已经注册了, 所以我们可以直接赋值就可以了。

 

在frame中只可以改变ICON ,为了改变图标我们重写窗口类我很不划算, 在MFC中为我们提供了一个函数AfxRegisterWndClass 直接改变icon详见MSDN

cs.lpszName = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW, 0, 0,

LoadIcon(NULL, IDI_WARNING));

这样就直接改变了frame中Icon。 

我们也可以在CStyleView中调用这个函数 来改变窗口的 画刷, 光标。

 

窗口创建之后改变外观

用SetWinowLong函数 具体见MSDN

LONG SetWindowLong(   HWND hWnd,      // handle of window  

 int nIndex,     // offset of value to set   

 LONG dwNewLong   // new value );

在CMainFrame的OnCreate中调用SetWindowLong

    SetWindowLong(m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);

这样就可以去掉了文档标题是窗口标题了。

我们可以通过GetWindowLong函数得到当前窗口的类型。 详见MSDN

   SetWindowLong(m_hWnd, GWL_STYLE, GetWindowLong(m_hWnd, GWL_STYLE) & ~WS_MAXIMIZEBOX);

这样就可以灰掉窗口的最大化窗口了。

 

窗口创建之后改变窗口类

上面的是改变窗口的大小和最大化最小化等等的按钮。

我们可以用SetClassLong来改变创建之后的窗口类的参数 例如 光标, 鼠标, 画刷 等等。

在单文档的应用程序中, 在CMainFrame类中只可以改变Icon 调用:

在OnCreate函数中

SetClassLong(m_hWnd, GCL_HICON, (LONG)LoadIcon(NULL, IDI_QUESTION));

可以改变application的icon。

 

在VIEW类中改变brush cursor background。

在view类中调用

SetClassLong(m_hWnd, GCL_HBRBACKGROUND, (LONG)GetStockObject(DKGRAY_BRUSH));

改变了VIEW的背景为灰色。

 

实现一个每一秒中自动换Icon的功能。

Precondition 

在resources 中添加3个icon的资源。

 

1. 首先在CMainFrame类中添加一个数组用于存放资源的句柄。

   在类中添加 HICON m_hIcon[3]; 的一个数组。

2. 在CMainFrame 函数中加载Icon用LoadIcon这个函数。

 

   HICON LoadIcon(   HINSTANCE hInstance,// handle to application instance    LPCTSTR lpIconName   // icon-name string or icon resource                            // identifier );

 

   如果用的系统的Icon话, LoadIcon这函数的第一个参数必须为NULL。

   如果用的是自己定义的Iicon的话, 第一个参数是这个应用程序的一个实例句柄。 第二参数是一个是icon的icon-name string 可以通过MAKEINTRESOURCE这个宏把资源的ID号转换为资源的字符串名字。

 

LPTSTR MAKEINTRESOURCE(   WORD wInteger // integer to convert );

 

   得到应用程序实例句柄我们可以通过几种方法:

   第一种: AfxGetInstanceHandle() 函数获得当前应用程序的实例句柄。

   第二种: 因为CStyleApp这个类是从CWinApp这个类中继承过来的所以继承了m_hInstance 这个变量, 这个变量就是应用程序的实例句柄。因为MFC在全局中建立了一个CStyleApp中变量 theApp 如果在CMainFrame中得到这个变量就可以得到应用程序的实例句柄。 在CMainFrame中用到全局变量需要声明这个变量 添加extern CStyleApp theApp; 这样就在CMainFrame中用theApp了。

theApp.m_hInstance.

   第三种: CWinApp* AfxGetApp( ); 返回的是一个CWinApp的指针。这样可以调用它的实例句柄。

 

3. 设置一个定时器在OnCreate中

我们这里调用的是CWND中的定时器。  

 UINT SetTimer( UINT nIDEvent, UINT nElapse, void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD) );

第一个参数 定时器的ID 第二个参数是设置的时间 第三个参数是处理函数, 如果设置为NULL 发送WM_TIME消息让消息处理系统调来处理。

   CWnd::SetTimer(1, 1000, NULL);

 

4. 在CMainFrame类中添加一个WM_TIME的消息处理函数。

 

   static int index = 1;

SetClassLong(m_hWnd, GCL_HICON, (LONG)m_hIcons[index]);

index = ++index % 3;

这样就可以定义出一个会随时间改变的ICON。

 

工具栏的编程   ToolBar

工具栏在resource中添加一个工具栏Item它的ID和menu中的菜单中的一个菜单的Id一样, 那么这个工具栏的Item就代表着那个菜单。

E.g

在resourcesiView中在帮助的下面添加一个菜单, 叫TEST 它的ID叫ID_TEST 并且建立对应的command消息响应函数,弹出对话框。

在resourcesView的ToolBar中建立一个Item他的ID 也叫ID_TEST 这样她们就关联起来了啊。

Click两个都是一样的。

 

添加一个自己的工具栏

在MSDN中查看CToolBar 提供了两种创建工具栏的方法

1. 首先在resourcesView中创建一个自己的ToolBar, ToolBar上的Item自己设定。

2. 在CMainFrame中添加一个CToolBar的类成员, 构造一个CToolBar的变量。

3. 调用CToolBar的Create 或者CteateEX  参考MSDN

   可以参考CMainFrame中构造ToolBar的方法。

 

if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP

| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||

!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))

{

TRACE0("Failed to create toolbar/n");

return -1;      // fail to create

}

4.  调用LoadToolBar这个函数加载资源。

5. 调用CToolBar的成员函数EnableDocking(CBRS_ALIGN_ANY);设置 这个对象是可以停靠的。 如果不设置这个那么工具栏将不可以悬浮。

6. 再调用CMainFrame::EnableDocking(CBRS_ALIGN_ANY);设置框架类可以被停靠。 

7. 最后在调用CMainFrame中的函数DockControlBar(&m_wndToolBar);停靠工具栏。

8. 我们还可以通过在菜单栏上设置一个Item并且设置command消息处理函数。

在处理函数中写上

if(m_toolBar.IsWindowVisible())

{

    m_toolBar.ShowWindow(SW_HIDE);

}

else

{

m_toolBar.ShowWindow(SW_SHOW);

}

CWnd::IsWindowVisible 当有WS_VISIBLE的时候 返回TRUE.用IsWindowVisible来返回ToolBar是不是可见的。

 

当我调用这个处理的时候 点击菜单里的Item来显示或者隐藏工具栏。但是发现虽然ToolBar消失了, 但是这个工具条还在。这个时候工具栏的停靠位子有所变化, 这个时候需要调用

CFrameWnd::RecalcLayout 函数。 

void RecalcLayout( BOOL bNotify = TRUE );

在上面的程序后面接上

RecalcLayout();

当把工具栏拖出来, 处于浮空的ToolBar的时候发现, 然后点击菜单来显示或者隐藏ToolBar发现 当浮空的时候ToolBar的工具条不会隐藏。 这个时候我们还需要调用一个函数

DockControlBar(&m_toolBar);

 

显示或隐藏工具栏的第二种方法

这个时候调用一个函数

ShowControlBar(&m_toolBar, !m_toolBar.IsWindowVisible(), FALSE);  具体调用参见MSDN。 ShowControlBar是CFrameWnd框架类的一个函数。

 

9. 我们还需要标记菜单的Item。当选中是标记, 当隐藏时取消标记。这个时候我们需要对这个Item的 UPDATE_COMMAND_UI进行响应。建立消息响应来标记活隐藏标记。 

调用CCmdUI的SetCheck();这个函数。来标记或者取消标记。

pCmdUI->SetCheck(m_toolBar.IsWindowVisible()); 具体用法参见MSDN。

 

状态栏的编写

1.  首先construct 一个CStatusBar的对象。

2.  然后调用变量的Create函数把状态栏窗口和一个CStatusBar的对象绑定。

 

CStatusBar::Create

BOOL Create( CWnd* pParentWnd, DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_BOTTOM, UINT nID = AFX_IDW_STATUS_BAR );

在MFC中是这样调用的:

if (!m_wndStatusBar.Create(this) || !m_wndStatusBar.SetIndicators(indicators,

 sizeof(indicators)/sizeof(UINT)))

{

TRACE0("Failed to create status bar/n");

return -1;      // fail to create

}

m_wndStausBar.Create(this), 其他的参数都用默认的参数。 后来条用m_wndStatusBar.Setindicators(indicators, sizeof(indicators)/sizeof(UINT));

Indicators 是一个数组储存字符串ID和每一个指示符。 后面一个参数是数组里面的数是多少个。

可以添加indicator 在数组中, 首先在String Table 中添加字符串ID , 然后把字符串ID添加在indicators的数组里面。这样就可以在状态栏中显示了。 

有三种方法更新状态栏上的字符。

1. Call CWnd::SetWindowText to update the text in pane 0 only.

2. Call CCmdUI::SetText in the status bar’s ON_UPDATE_COMMAND_UI handler.

3. Call SetPaneText to update the text for any pane.

 

我们可以把系统当前时间显示在状态栏上。

这个时候需要用到 CTime

 CTime t = CTime::GetCurrentTime();

CString timeStr = t.Format("%H:%M:%S");

格式输出到一个字符串中。 

然后调用 m_wndStatusBar.SetPaneText(1, timeStr);

第一个参数是索引Index of the pane whose text is to be set。

timeStr是要显示的字符串了。

如果不知道要显示的索引, 我们可用调用m_wndStatusBar的一个成员函数CommandToIndex(IDS_TIMER); 括号里面的参数是表示要显示的字符串ID。

 

运行程序, 我们会发现时钟的秒不能显示。 这个是因为状态栏空间不够所以不能完全显示内容。 

我们可以调用SetPaneInfo();

CStatusBar::SetPaneInfo

void SetPaneInfo( int nIndex, UINT nID, UINT nStyle, int cxWidth );

 

 函数改变状态栏空间大小。

 

为了获得字符串的显示宽度, 我们需要调用GetTextExtent(Cstring str);来返回字符创的空间大小, CSize。

CClientDC dc(this);

CSize sz = dc.GetTextExtent(timeStr);

之后再调用SetPaneText();来显示内容

 

这个时候发现时间是不动的。 需要动, 要把刚刚这段代码放到SetTimer的响应函数中不停调用显示时间。 

 

创建一个进度栏

进度栏的类是CProgressCtrl。 定义一个变量, 并且调用Create初始化一个进度栏。

 

CProgressCtrl::Create

BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );

第一个参数是一个窗口类, E.G  WS_CHILD | WS_VISIBLE | PBS_SMOOTH 

第二个参数是一个矩形区域。

 

CProgressCtrl m_progressCtrl;

m_progressCtrl.SetPos(50); 设置到中间。 

 

如果我们想把这个矩形区域显示在状态栏里。 

 

首相我们在CMainFrame类中编写这样一段程序

CRect rect;

m_wndStatusBar.GetItemRect(2, &rect);

m_progressCtrl.Create(WS_CHILD| WS_VISIBLE| PBS_SMOOTH, rect,

&m_wndStatusBar, 1);

注意这里的&m_wndStatusBar是进度条的父窗口。 在View类中创建进度条时, 父类窗口就是this, 代表这个对象的指针。

 

运行程序发现进度条并没有出现, 我们在CRect rect ; 这里设置断点, 运行函数, 看断点的值发现rect的值是一个无效的值, 这个时候我们猜想, 在OnCreat 结束钱状态栏还没有初始化好。 这样我们可以在OnCreate之后调用一个函数来处理进度条。

我们可以自己定义一个消息,在OnCreate中把这个消息投递到消息队列中,来处理这个函数。

首先我先定义一个消息, 在window中消息都是用一个整数来表示的,在CMainFrame的头文件中添加一个消息。 #define UM_PROGRESS WM_USER+1

因为window的很多消息已经占用了很多的整数, 我们胡乱定义很可可能和系统冲突, WM_USER以下的是系统消息保留的。 以上的可以是用户自己定义的。这样我们就定义了一个UM_PROGRESS 的消息。添加完这个消息后, 要有相应的消息响应函数来处理这个消息。

protected:

//{{AFX_MSG(CMainFrame)

afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);

afx_msg void OnTimer(UINT nIDEvent);

afx_msg void OnTest();

afx_msg void OnAppendToolbar();

afx_msg void OnUpdateAppendToolbar(CCmdUI* pCmdUI);

afx_msg void OnPaint();

//}}AFX_MSG

先要在头文件的这段代码后面添加

  afx_msg void OnProgress();

DECLARE_MESSAGE_MAP()

 

参考MFC的程序;

然后在。CPP文件中

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)

//{{AFX_MSG_MAP(CMainFrame)

ON_WM_CREATE()

ON_WM_TIMER()

ON_COMMAND(ID_TEST, OnTest)

ON_COMMAND(ID_APPEND_TOOLBAR, OnAppendToolbar)

ON_UPDATE_COMMAND_UI(ID_APPEND_TOOLBAR, OnUpdateAppendToolbar)

ON_WM_PAINT()

//}}AFX_MSG_MAP

ON_MESSAGE(UM_PROGRESS, OnProgress)

END_MESSAGE_MAP()

消息响应函数是通过 ON_MESSAGE() 把消息和消息处理函数关联起来的。

 

最后在添加消息处理函数

Void CMainFrame::OnProgress()

 

CRect rect;

m_wndStatusBar.GetItemRect(2, &rect);

m_progressCtrl.Create(WS_CHILD| WS_VISIBLE| PBS_SMOOTH, rect,

&m_wndStatusBar, 1);

 

在这个函数中处理进度条。在OnCreate函数中用PostMessage();

不能用SendMessage(); 因为 SendMessage是直接调用了处理函数, 这个时候状态栏还没有处理好。 

 

现在运行应用程序, 这个时候progress显示在状态栏上, 但是当我们拉伸或者缩放的时候进度栏 不再第二个状态栏上的时候而是在别的地方 这是为什么呢??

每当窗口的尺寸变化的时候就会重绘发送ON_PAIN这个消息我们可以创建响应函数, 在这个函数中编写上面的程序。

当改变尺寸的时候会当初dialog错误, 这是因为每当发送一个ON_PAIN消息函数的时候都会Create一个进度栏, 所照成了错误。应该判断是否已经创建没有创建的时候创建, 创建了移动窗口。

修改程序为一下:

CRect rect;

m_wndStatusBar.GetItemRect(2, &rect);

if(m_progressCtrl.m_hWnd == NULL)

m_progressCtrl.Create(WS_CHILD| WS_VISIBLE| PBS_SMOOTH, rect,

&m_wndStatusBar, 1);

else

m_progressCtrl.MoveWindow(rect);

 

如果要进度栏里的进度增加的话, 我们可以调用CProgressCtrl类的一个StepIt函数来增长, 把发在OnTimer(); 里面每次调用就会发送一个OnPaint函数来重绘进度栏。 

 

现在我们想在在状态栏上显示当前鼠标的位置, 在View类中添加ON_MOUSEMOVE处理函数。

CString pointStr;

pointStr.Format("x=%d y=%d", point.x, point.y);

((CMainFrame*)GetParent())->m_wndStatusBar.SetPaneText(0, pointStr);

运行程序显示出位置。因为状态栏是框架类的, 所以首先要先获得框架类的指针, 通过GetParent() 这个函数来获得, 转换为CMainFrame指针类型。

需要在View中加入头文件“MainFrm.h”

或者调用 ((CMainFrame*)GetParent())->SetMessageText(pointStr);

 

也可以这样

((CMainFrame*)GetParent())->GetMessageBar()->SetWindowText(pointStr);

GetMessageBar()是一个CMainFrame类的函数, 无需知道状态栏的变量。

 

创建启动画面

在菜单上点击工程->添加到工程->组件和空间- >Visual C++ components->solash Screen ->insert.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值