PropertyPage在非英文版Win10中变大变形

PropertyPage变大变形问题

问题描述

  1. 手上维护的一个Tool, 开发平台是 Win7 + VS2008 MFC C++
  2. 由于前段时间微软发布声明不再对Win7做更新及支持,以及现在电脑基本上出厂预装Win10,所以不得不支持Win10了。由于不是专业的软件公司,上面要求能在Win10上正常使用就行了。
  3. 在迁移至Win10过程中发现部分也面出现变形的情况,原本在Win7上能正常显示的页面,在Win10 笔记本中中会在Height及Width方向上增大,导致页面超出屏幕,底部有些控件会显示不出来;在PC上页面虽然变大,由于PC屏幕较大的缘故,可以显示完全。
  4. 经过测试发现,基于一般Dialog的页面在Win10上不会出现变形,而基于PropertyPage的页面则会出现此问题。
  5. 刚开始猜测与高DPI有关,因为基于一般Dialog的页面在“放大模式为125%”(我这样称呼哈)同样也出现了变形,不过五一过后回来再测,发现一般Dialog的页面居然不会变形了,而PropertyPage仍然会,猜测或许是微软修复了对于一般Dialog的这个问题。

解决方式

方式1

本想着在Win10上放大了,超出屏幕,干脆加个VScrollBar或许就可解决该问题,不过加上倒是看得完了,但是由于在该页面使用了GDI绘制,而绘制的坐标是固定的,滚动VScrollBar时,GDI绘制的并未随着页面滚动,算是失败了。(不过通过加滚动条应该是可以解决的,就是太懒,不想去弄那些坐标,感觉挺麻烦…)

方式2

根据系统版本使用不同的对话框资源,这个也试了试,发现在Win10上不能获取正确的系统版本,不过下载的示例又是可以的,搞不懂,不知道是哪里设置错了,还是太菜啊。

方式3

获取屏幕宽度、高度,根据屏幕比例,调整页面的大小,不过感觉通过调整Add的每一个Page的高度,最终并不能调整高度,不是说PropertySheet的高度是根据最大的PropertyPage的大小来确定的吗。

方式4

使用TabCtrl替换原有的ProperSheet,不过这个就是比较麻烦,原有的对话框类基本上是不能使用了,需要根据TabCtrl的实现方法,重新实现每一个对话框类。不过唯一值得庆幸的是该方法是可行的,且效果与使用PropertySheet基本无差别。 虽然在实作前,有写Demo程序在Win10上测试,不会变形,但还是有点担心最终不可行。

方式5

虽然TabCtrl可行,但是这仅使用于我这个Tool中Page较少的情况,对于Page很多的情况改动起来就贼难受了,下面这种方法是可行且改动很小的方式,甚至比改TabCtrl还要小很多。这种方式是CSDN上一位资源主提供的,我也是下载了示例程序修改了一下适用我的程序,以下是主要Source code。

.h

/*****************************************************************************************
 File:     CBPropertySheet.h
 Author:   Ovidiu Cucu - Microsoft MVP Viusal C++ 
                         Codeguru nickname: ovidiucucu
                         Homepage: www.codexpert.ro
 Updated:  January 02, 2010
 Contents: CCBPropertySheet class definition.
 Remarks:  CCBPropertySheet is an MFC-extension class for creating properties sheets
           which are using a custom font.
******************************************************************************************/
#pragma once

#if _MSC_VER < 1300 // VS6.0 and older
#define DOMODAL_RET int
#else
#define DOMODAL_RET INT_PTR 
#endif 

class CCBPropertySheet : public CPropertySheet
{
	DECLARE_DYNAMIC(CCBPropertySheet)
public:
	CCBPropertySheet(UINT nIDCaption, CWnd* pParentWnd = NULL, UINT iSelectPage = 0);
	CCBPropertySheet(LPCTSTR pszCaption, CWnd* pParentWnd = NULL, UINT iSelectPage = 0);
   virtual ~CCBPropertySheet() = 0;

// Attributes
private:
   static __declspec(thread) WORD m_wFontSize;
   static __declspec(thread) LPCTSTR m_pszFontFaceName;

// Operations
public:
   // call this function to create a modal property sheet with custom font.
   DOMODAL_RET DoModal(LPCTSTR pszFontFaceName, WORD wFontSize);

   // call this function to create a modal property sheet with default font.
   virtual DOMODAL_RET DoModal();

   // call this function to create a modeless property sheet with custom font.
	BOOL Create(LPCTSTR pszFontFaceName, WORD wFontSize, CWnd* pParentWnd = NULL, 
               DWORD dwStyle = (DWORD)-1, DWORD dwExStyle = 0);

   // call this function to create a modeless property sheet with default font.
	BOOL Create(CWnd* pParentWnd = NULL, DWORD dwStyle = (DWORD)-1, DWORD dwExStyle = 0);

// Overides
protected:
   virtual void BuildPropPageArray();

// Implementation
private:
   static int CALLBACK PropSheetProc(HWND hWndDlg, UINT uMsg, LPARAM lParam);
   void Init(LPCTSTR pszFontFaceName, WORD wFontSize);
};

.cpp

/*****************************************************************************************
 File:     CBPropertySheet.cpp
 Author:   Ovidiu Cucu - Microsoft MVP Viusal C++ 
                         Codeguru nickname: ovidiucucu
                         Homepage: www.codexpert.ro
 Updated:  January 02, 2010
 Contents: CCBPropertySheet class implementation.
 Remarks:  CCBPropertySheet is an MFC-extension class for creating properties sheets
           which are using a custom font.
******************************************************************************************/
#include "stdafx.h"

#include "CBPropertySheet.h"
#include <AFXPRIV.H>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

WORD __declspec(thread) CCBPropertySheet::m_wFontSize = 0;
LPCTSTR __declspec(thread) CCBPropertySheet::m_pszFontFaceName = NULL;

IMPLEMENT_DYNAMIC(CCBPropertySheet, CPropertySheet)

/*****************************************************************************************
 Function:   CCBPropertySheet::CCBPropertySheet
 Purpose:    Constructs a CCBPropertySheet object.
 Parameters: - nIDCaption: Resource ID of the caption to be used for the property sheet.
             - pParentWnd: Parent window (default NULL).
             - iSelectPage: Index of the page that will initially be on top (default 0).
******************************************************************************************/
CCBPropertySheet::CCBPropertySheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage)
	:CPropertySheet(nIDCaption, pParentWnd, iSelectPage)
{
}

/*****************************************************************************************
 Function:   CCBPropertySheet::CCBPropertySheet
 Purpose:    Constructs a CCBPropertySheet object.
 Parameters: - pszCaption: The string to be displayed on the property sheet caption. 
             - pParentWnd: Parent window (default NULL).
             - iSelectPage: Index of the page that will initially be on top (default 0).
******************************************************************************************/
CCBPropertySheet::CCBPropertySheet(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage)
	:CPropertySheet(pszCaption, pParentWnd, iSelectPage)
{
}

/*****************************************************************************************
 Function:   CCBPropertySheet::~CCBPropertySheet
 Purpose:    Destructs a CCBPropertySheet object.
******************************************************************************************/
CCBPropertySheet::~CCBPropertySheet()
{
}

/*****************************************************************************************
 Function:   CCBPropertySheet::PropSheetProc
 Purpose:    Application-defined callback function that the system calls when the property 
             sheet is being created and initialized
 Parameters: - hWndDlg: Handle to the property sheet dialog box.
             - uMsg: Message being received
             - lParam: Additional information about the message.
 Remarks:    If uMsg is PSCB_PRECREATE, lParam is the address of a dialog template in 
             memory. This template is in the form of a DLGTEMPLATE or DLGTEMPLATEEX 
             structure followed by one or more DLGITEMTEMPLATE structures.
******************************************************************************************/
int CALLBACK CCBPropertySheet::PropSheetProc(HWND hWndDlg, UINT uMsg, LPARAM lParam)
{
   switch(uMsg)
   {
   case PSCB_PRECREATE:
      {
         if((m_wFontSize > 0) && (NULL != m_pszFontFaceName))
         {
            
            LPDLGTEMPLATE pResource = (LPDLGTEMPLATE)lParam;
            CDialogTemplate dlgTemplate(pResource);
            dlgTemplate.SetFont(m_pszFontFaceName, m_wFontSize);
            memmove((void*)lParam, dlgTemplate.m_hTemplate, dlgTemplate.m_dwTemplateSize);
         }
      }
      break;
   }
   return 0;
}

/*****************************************************************************************
 Function:   CCBPropertySheet::Create
 Purpose:    Creates a modeless property sheet.
 Parameters: - pszFontFaceName: Font face name.
             - wFontSize: Font size.
             - pParentWnd: parent window (default NULL).
             - dwStyle: style (default -1).
             - dwExStyle: extended style (default 0).
 Remarks:    Call this function for creating modeless property sheets with CUSTOM FONT.
******************************************************************************************/
BOOL CCBPropertySheet::Create(LPCTSTR pszFontFaceName, WORD wFontSize, CWnd* pParentWnd, 
                              DWORD dwStyle, DWORD dwExStyle)
{
   Init(pszFontFaceName, wFontSize);
   return CPropertySheet::Create(pParentWnd, dwStyle, dwExStyle);
}

/*****************************************************************************************
 Function:   CCBPropertySheet::Create
 Purpose:    Creates a modeless property sheet.
 Parameters: - pParentWnd: parent window (default NULL).
             - dwStyle: style (default -1).
             - dwExStyle: extended style (default 0).
 Remarks:    Call this function for creating modeless property sheets with DEFAULT FONT.
******************************************************************************************/
BOOL CCBPropertySheet::Create(CWnd* pParentWnd, DWORD dwStyle, DWORD dwExStyle)
{
   Init(NULL, 0);
   return CPropertySheet::Create(pParentWnd, dwStyle, dwExStyle);
}

/*****************************************************************************************
 Function:   CCBPropertySheet::DoModal
 Purpose:    Creates a modal property sheet.
 Parameters: - pszFontFaceName: Font face name.
             - wFontSize: Font size.
 Remarks:    Call this function for creating modal property sheets with CUSTOM FONT.
******************************************************************************************/
DOMODAL_RET CCBPropertySheet::DoModal(LPCTSTR pszFontFaceName, WORD wFontSize)
{
   Init(pszFontFaceName, wFontSize);
   return CPropertySheet::DoModal();
}

/*****************************************************************************************
 Function:   CCBPropertySheet::DoModal
 Purpose:    Creates a modal property sheet.
 Remarks:    Call this function for creating modal property sheets with DEFAULT FONT.
******************************************************************************************/
DOMODAL_RET CCBPropertySheet::DoModal()
{
   Init(NULL, 0);
   return CPropertySheet::DoModal();
}

/*****************************************************************************************
 Function:   CCBPropertySheet::Init
 Purpose:    Initializes font info as well as PROPSHEETHEADER structure in order to 
             use application-defined callback function (CCBPropertySheet::PropSheetProc).
 Parameters: - pszFontFaceName: Font face name.
             - wFontSize: Font size.
 Remarks:    Called either from Create and DoModal functions.
             If m_wFontSize = 0 or pszFontFaceName is NULL then default font will be used.
******************************************************************************************/
void CCBPropertySheet::Init(LPCTSTR pszFontFaceName, WORD wFontSize)
{
   m_pszFontFaceName = pszFontFaceName;
   m_wFontSize = wFontSize;

   if((m_wFontSize > 0) && (NULL != m_pszFontFaceName))
   {
      m_psh.pfnCallback = &CCBPropertySheet::PropSheetProc;
      m_psh.dwFlags |= PSH_USECALLBACK;
   }
}

/*****************************************************************************************
 Function: CCBPropertySheet::BuildPropPageArray
 Purpose:  Overrides CPropertySheet::BuildPropPageArray
******************************************************************************************/
void CCBPropertySheet::BuildPropPageArray()
{
   CPropertySheet::BuildPropPageArray();

   if((m_wFontSize > 0) && (NULL != m_pszFontFaceName))
   {
      LPCPROPSHEETPAGE ppsp = m_psh.ppsp;
      const int nSize = static_cast<int>(m_pages.GetSize());

      for(int nPage = 0; nPage < nSize; nPage++)
      {
         const DLGTEMPLATE* pResource = ppsp->pResource;
         CDialogTemplate dlgTemplate(pResource);
         dlgTemplate.SetFont(m_pszFontFaceName, m_wFontSize);
         memmove((void*)pResource, dlgTemplate.m_hTemplate, dlgTemplate.m_dwTemplateSize);

         (BYTE*&)ppsp += ppsp->dwSize;
      }
   }
}

在使用过程中主要需要添加这个类,然后你的Sheet类直接继承于CCBPropertySheet类而不是CPropertySheet, 例如:

Sheet类.h

#pragma once
#include "CBPropertySheet.h"
#include "Prop1.h"
#include "Prop2.h"

// CPropertySheetDemo
class CPropertySheetDemo : public CCBPropertySheet
{
	DECLARE_DYNAMIC(CPropertySheetDemo)
public:
	CPropertySheetDemo(UINT nIDCaption, CWnd* pParentWnd = NULL, UINT iSelectPage = 0);
	virtual ~CPropertySheetDemo();
// Attributes
private:
	CProp1 m_page1;
	CProp2 m_page2;

// Implementaion
protected:
	DECLARE_MESSAGE_MAP()

};

Sheet类.CPP

// PropertySheetDemo.cpp : implementation file
//

#include "stdafx.h"
#include "LingoTest.h"
#include "PropertySheetDemo.h"


// CPropertySheetDemo

IMPLEMENT_DYNAMIC(CPropertySheetDemo, CCBPropertySheet)

CPropertySheetDemo::CPropertySheetDemo(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage)
	: CCBPropertySheet(nIDCaption, pParentWnd, iSelectPage)
{
   AddPage(&m_page1);
   AddPage(&m_page2);
}

CPropertySheetDemo::~CPropertySheetDemo()
{
}

BEGIN_MESSAGE_MAP(CPropertySheetDemo, CCBPropertySheet)
END_MESSAGE_MAP()

至于Add 至 PropertySheet 的PropertyPage,例如这里的CProp1、CProp2的实现方式就是最基本的PropertyPage的实现方式继承于CPropertyPage。

在对话框中使用 CPropertySheetDemo


// LingoTestDlg.h : header file
//

#pragma once

class CPropertySheetDemo;

// CLingoTestDlg dialog
class CLingoTestDlg : public CDialogEx
{
// Construction
public:
	CLingoTestDlg(CWnd* pParent = NULL);	// standard constructor
	~CLingoTestDlg();

// Dialog Data
	enum { IDD = IDD_LINGOTEST_DIALOG };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV support


// Implementation
protected:
	HICON m_hIcon;

	// Generated message map functions
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()

public:
	afx_msg void OnBnClickedButtonTest();
	BOOL m_nDefault;

private:
	CPropertySheetDemo *m_pps;
};


// LingoTestDlg.cpp : implementation file
//

#include "stdafx.h"
#include "LingoTest.h"
#include "LingoTestDlg.h"
#include "PropertySheetDemo.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CLingoTestDlg dialog
CLingoTestDlg::CLingoTestDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CLingoTestDlg::IDD, pParent)
	, m_nDefault(FALSE)
{
	m_pps = NULL;
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CLingoTestDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Radio(pDX, IDC_RADIO_DEFAULT, m_nDefault);
}

BEGIN_MESSAGE_MAP(CLingoTestDlg, CDialog)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDC_BUTTON_TEST, &CLingoTestDlg::OnBnClickedButtonTest)
END_MESSAGE_MAP()


// CLingoTestDlg message handlers
BOOL CLingoTestDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.
	...
	// TODO: Add extra initialization here

	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CLingoTestDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	...	
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CLingoTestDlg::OnPaint()
{
	...
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CLingoTestDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}


void CLingoTestDlg::OnBnClickedButtonTest()
{
	// TODO: Add your control notification handler code here
	UpdateData();

	CPropertySheetDemo pps(IDS_PROPERTYSHEET_CAPTION, this);
	if (0 == m_nDefault)
	{
		pps.DoModal();
	}
	else
	{
//		创建模式属性页对话框
//		pps.DoModal(strFontFaceName, m_nSize);

		//创建非模式属性页对话框
		if (m_pps == NULL)
		{	
			int m_nSize = 8;
			CString strFontFaceName;
			strFontFaceName.Format(_T("Microsoft Sans Serif"));			
			m_pps = new CPropertySheetDemo(IDS_PROPERTYSHEET_CAPTION, this);	 
			m_pps->Create(strFontFaceName, m_nSize, this, WS_SYSMENU | WS_POPUP | WS_CAPTION | DS_MODALFRAME | DS_CONTEXTHELP | WS_VISIBLE);
//			m_pps->SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
		}
		else
		{
			if (m_pps->GetSafeHwnd())
			{
				if (m_pps->IsWindowVisible())
				{
					m_pps->ShowWindow(SW_HIDE);
				}
				else
				{
					m_pps->ShowWindow(SW_SHOW);
				}
			}
		}

	}	
}

CLingoTestDlg::~CLingoTestDlg()
{
	if(m_pps)
	{
		if (m_pps->GetSafeHwnd())
		{
			m_pps->DestroyWindow();
		}
		delete m_pps;
		m_pps = NULL;
	}
}


主要在 CLingoTestDlg::OnBnClickedButtonTest()中,原有DoModal()创建指定字体模态属性页OK,但我的程序中需要创建非模态属性页对话框,就得使用非模态的Create的方式了。

最终经过验证,在我的程序中使用这种方式比较OK,没有较大的改动,由此PropertySheet、PropertyPage在非英文版Win10中变大变形的问题基本得以解决,问题应该也比较清楚是对话框字体的原因,不过具体深层次的原因,目前以我的水平是无法深入了解了。
Tips: 另外通过测试发现在150%时,这种方式表现的不如CTabCtrl…

以上则为解决PropertySheet\PropertyPage在Win10上被拉大的情况的相关经历和方式,供需要的童靴参考。

相关链接:
https://download.csdn.net/download/yayun/10503607

感谢资源主提供的Code,虽然可能看不到,但还是聊表谢意 ^ _ ^

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值