2013-07-30 25 views
9

Trong Windows Volume Mixer, khi ứng dụng của bạn phát âm thanh, nó sẽ thêm biểu tượng ứng dụng và thanh trượt âm lượng tùy chỉnh để điều chỉnh âm lượng cụ thể cho ứng dụng đó ... Tuy nhiên, khi bạn sử dụng một biểu tượng có kích thước lớn cho ứng dụng của bạn (đặc biệt quan trọng trong DPI cao khi Windows điều chỉnh biểu tượng của bạn cho Thanh tác vụ, v.v.), biểu tượng trong Bộ trộn âm lượng không chia tỷ lệ chính xác. Cụ thể, mã sau đây là những gì tôi sử dụng để đặt biểu tượng của ứng dụng:Kích cỡ biểu tượng Windows Volume Mixer quá lớn

// set icons the normal way 
cWnd.SetIcon(theApp.LoadIcon(res_id), FALSE); 
cWnd.SetIcon(theApp.LoadIcon(res_id), TRUE); 

// set hi-res if available 
OSVERSIONINFO osv; 
osv.dwOSVersionInfoSize = sizeof(osv); 
if (GetVersionEx(&osv)) { 
    // if we're Vista or more recent, use hi-def icons 
    if (osv.dwMajorVersion >= 6) { 
     HICON hIcon = (HICON)::LoadImage(theApp.m_hInstance, MAKEINTRESOURCE(res_id), IMAGE_ICON, 256, 256, LR_SHARED); 
     if (hIcon) { 
      cWnd.SetIcon(hIcon, TRUE); 
     } 
    } 
} 

Thủ phạm là phần "hi-res nếu có". Nếu tôi bao gồm điều đó, biểu tượng Taskbar trông rất tuyệt nhưng Volume Mixer không bị thu nhỏ và trông khủng khiếp. Nếu tôi loại trừ rằng, biểu tượng Taskbar trông xấu (rộng khủng khiếp) nhưng Mixer Khối lượng ít nhất là kích thước phù hợp:

Desktop Scaling 125% with 256x256 icon set Desktop Scaling 125% with regular icons

Có ai tìm thấy một giải pháp mà làm cho nó để cả hai biểu tượng tìm kiếm tốt ?

EDIT: Trong tệp biểu tượng của tôi, tôi có các độ phân giải sau: 256x256, 48x48, 32x32, 24x24 và 16x16, tất cả 32 bit. Các 256x256 một là PNG nén, những người khác là nguyên. Tất cả các kích thước nhìn tuyệt vời ở độ phân giải mà họ có trong tập tin (tôi đã cố gắng để đặt ICO ở đây hoặc trong imgur nhưng dường như không cho phép các biểu tượng). Ngoài ra tôi đã thử bao gồm một số hình ảnh 8-bit nhưng điều đó dường như không thay đổi mọi thứ.

EDIT: Tôi đang sử dụng GetDeviceCaps(hdc, LOGPIXELSX) (và Y) để xác định Tỷ lệ màn hình. Thông thường tỷ lệ máy tính để bàn là 100% và tôi nhận được kết quả 96 bình thường. Nhưng ngày càng nhiều, tôi thấy máy tính mặc định là 125%. Điều này có thể được thay đổi bằng cách kích chuột phải vào Desktop, Personalize, khác: Display ... có một thanh trượt ở đó (yêu cầu đăng xuất/in để thay đổi).

EDIT: Tôi cũng muốn chỉ ra rằng ICON khay chịu số phận phát hành tương tự khi ở chế độ DPI cao (tức là khi sử dụng Shell_NotifyIcon). Trong trường hợp này, tuy nhiên, tôi có thể sử dụng GetDeviceCaps(hdc, LOGPIXELSX) để xác định những gì Windows muốn .. nếu tôi có kích thước, cung cấp nó trực tiếp, nếu không cung cấp 256x256 một và Windows không quy mô nó một cách chính xác.

EDIT: Nỗi buồn xảy ra sau đó. Sự cố này có thể là sự cố Windows. Trong khi chụp ảnh cho mục đích trình diễn, tôi nhận thấy biểu tượng Volume Mixer chính nó trông kém. Để so sánh: Volume Mixer Comparison

EDIT cuối cùng: Như được mô tả bên dưới, giải pháp cho vấn đề là chia tỷ lệ biểu tượng. Vì vậy, các mã cuối cùng mà làm việc là để tải một con trỏ đến LoadIconWithScaleDown chức năng từ Comctl32.dll (không hiển thị) và sử dụng rằng nếu nó đã có sẵn, hoặc rơi trở lại "bình thường/cũ" cách:

HICON hIcon = 0; 
if (FAILED(comctl32Loader.LoadIconWithScaleDown(theApp.m_hInstance, MAKEINTRESOURCE(res_id), GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), &hIcon))) { 
    hIcon = theApp.LoadIcon(res_id); 
} 
cWnd.SetIcon(hIcon, FALSE); 
if (FAILED(comctl32Loader.LoadIconWithScaleDown(theApp.m_hInstance, MAKEINTRESOURCE(res_id), GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), &hIcon))) { 
    hIcon = theApp.LoadIcon(res_id); 
} 
cWnd.SetIcon(hIcon, TRUE); 

Trả lời

2

Có , Tôi có thể tái tạo sự cố bạn mô tả khi tôi sử dụng cùng một mã như được hiển thị trong câu hỏi. Như chúng ta đã xác định, vấn đề chỉ thể hiện ở các thiết lập DPI cao. Với tỷ lệ 100% (~ 96 dpi), ngay cả trên Windows Vista trở lên, bạn chỉ cần sử dụng phiên bản "lớn" của biểu tượng (SM_CXICONSM_CYICON; thường là 32x32 pixel) cho cửa sổ chứ không phải phiên bản pixel 256x256. Đó là những gì các ứng dụng đi kèm với Windows, bao gồm cả tập hợp Volume Mixer mà bạn đang thử nghiệm.

vấn đề này được đưa ra khi bạn đang sử dụng các thiết lập DPI cao, mà làm cho kích thước "lớn" đi lên:

╔════════════╦═════════════════╦═════════════════╗ 
║ DPI  ║ Large Icon Size ║ Small Icon Size ║ 
║   ║ (SM_C?ICON) ║ (SM_C?SMICON) ║ 
╠════════════╬═════════════════╬═════════════════╣ 
║ 96 (100%) ║  32x32  ║  16x16  ║ 
║ 120 (125%) ║  40x40  ║  20x20  ║ 
║ 144 (150%) ║  48x48  ║  24x24  ║ 
║ 192 (200%) ║  64x64  ║  32x32  ║ 
╚════════════╩═════════════════╩═════════════════╝ 

Mọi thứ hoạt động tốt bất kể DPI khi bạn nạp vào biểu tượng 256x256 pixel, bởi vì Windows là tự động giảm kích thước xuống kích thước yêu cầu. Điều đó tạo ra một biểu tượng chất lượng tốt hơn nhiều (không có tất cả các jaggies và các hiện vật khác) hơn là cố gắng mở rộng biểu tượng lên một biểu tượng 32x32 pixel. Vì vậy, đoán của bạn là chính xác, vấn đề thực sự liên quan đến việc mở rộng quy mô.

Tôi sẽ giả định rằng những gì bạn đang nhìn thấy trong trình trộn tập dữ liệu khi bạn sử dụng biểu tượng pixel 256x256 là lỗi — nên mở rộng biểu tượng lớn xuống kích thước mong đợi, đó là " biểu tượng "lớn (SM_C?ICON). Có lẽ, nó gọi hàm DrawIconEx với các tham số cxWidthcxHeight cả hai được đặt thành 0 và không phải là chuyển cờ DI_DEFAULTSIZE. Điều đó khiến cho biểu tượng được vẽ bằng kích thước thực tế của nó — rất lớn.

Bạn sẽ phải giải quyết vấn đề theo cách thủ công, bằng cách tự mở rộng biểu tượng. May mắn thay, Windows Vista giới thiệu một số chức năng được thiết kế một cách rõ ràng cho mục đích này. Cách dễ nhất để sử dụng trong trường hợp này là LoadIconWithScaleDown. Giống như tên cho thấy, nó hoạt động tương tự như các hàm cũ hơn LoadIcon/LoadImage, nhưng thay vì mở rộng biểu tượng quá nhỏ, nó giảm kích thước biểu tượng lớn hơn - hoàn hảo khi bạn có biểu tượng pixel khổng lồ, chất lượng cao 256x256 tệp ICO của bạn.

Thật không may, các chức năng này không có sẵn trên các phiên bản Windows cũ hơn, có khả năng sẽ có cùng một vấn đề khi được sử dụng ở các cài đặt DPI cao hơn. Bạn sẽ cần phải tìm các lựa chọn thay thế ở đó, hoặc chỉ giải quyết các biểu tượng bị lởm chởm, thu nhỏ trên các hệ điều hành cũ hơn này.

Mẫu mã:

#include <CommCtrl.h>     // include Common Controls header 
#pragma comment(lib, "comctl32.lib") // link to Common Controls library 

// Embed a standard manifest to use Common Controls v6 
#pragma comment(linker, "/manifestdependency:\"type='win32' "       \ 
         "name='Microsoft.Windows.Common-Controls' version='6.0.0.0' " \ 
         "processorArchitecture='*' "         \ 
         "publicKeyToken='6595b64144ccf1df' "       \ 
         "language='*'\"") 
// Load and set "large" icon (typically 32x32 pixels, but not necessarily) 
HICON hIconLg; 
if (SUCCEEDED(LoadIconWithScaleDown(g_hInstance, 
            MAKEINTRESOURCE(IDI_ICON), 
            GetSystemMetrics(SM_CXICON), 
            GetSystemMetrics(SM_CYICON), 
            &hIconLg))) 
{ 
    SendMessage(hWnd, WM_SETICON, ICON_BIG, reinterpret_cast<LPARAM>(hIconLg)); 
} 

// Load and set "small" icon (typically 16x16 pixels, but not necessarily) 
HICON hIconSm; 
if (SUCCEEDED(LoadIconWithScaleDown(g_hInstance, 
            MAKEINTRESOURCE(IDI_ICON), 
            GetSystemMetrics(SM_CXSMICON), 
            GetSystemMetrics(SM_CYSMICON), 
            &hIconSm))) 
{ 
    SendMessage(hWnd, WM_SETICON, ICON_SMALL, reinterpret_cast<LPARAM>(hIconSm)); 
} 

Lưu ý rằng để sử dụng các chức năng mới, bạn sẽ cần phải liên kết đến phiên bản 6 của thư viện điều khiển thông thường. Điều đó yêu cầu bạn hướng dẫn trình biên dịch liên kết trong comctl32.lib và nhúng tệp kê khai vào ứng dụng của bạn. Có thể thực hiện bằng cách sử dụng các mã số #pragma được chỉ định trong mã mẫu ở trên hoặc được định cấu hình trong thuộc tính của dự án của bạn. Nếu bạn không thực hiện một trong những điều này, bạn sẽ gặp lỗi thời gian liên kết hoặc lỗi "không tìm thấy thứ tự" khi bạn khởi chạy ứng dụng lần đầu tiên.

+0

Ồ, cảm ơn tất cả các chi tiết và phân tích của bạn. Trong tập tin ICO của tôi, tất cả các độ phân giải đều tốt ở các độ phân giải mà tôi cung cấp (xem EDIT ở trên).Ví dụ dưới của tôi "jaggy" hình ảnh thực sự được thu nhỏ bởi Windows (Tôi không có một ICO trông giống như trong tập tin ICO của tôi). Windows thực hiện điều này khi ở chế độ DPI cao hơn. Theo quan điểm của bạn, khi tôi thực hiện GetDeviceCaps trong quy mô desktop thông thường (100%), tôi nhận được 96 ... nhưng nếu tôi đặt máy tính để bàn của mình thành tỷ lệ 125% hoặc tỷ lệ 200% (nhấp chuột phải vào Desktop, Personalize, other: Display), Tôi nhận được một DPI và Windows khác nhau yêu cầu hình ảnh lớn hơn bắt đầu mở rộng ICON theo cách "xấu" này. – mark

+0

Net-net ở trên: nếu tôi "để Windows quyết định" ICO nào sẽ sử dụng ở chế độ DPI cao (tức là không có 'LoadImage' hoặc thông qua' GetSystemMetrics (SM_CXSMICON) ') thì nó chọn biểu tượng có độ phân giải thấp và tăng tỷ lệ (và tệ). – mark

+0

Chỉ để chắc chắn rằng tôi đã không mất trí, tôi đã sử dụng mã của bạn thay cho vị trí của tôi ... nó có vẻ 'tốt' ở mức 100% Desktop scaling. Tôi đặt máy tính để bàn của tôi để tỷ lệ 125%, và * cả hai * Khối lượng Mixer và các biểu tượng Taskbar trông nghèo (jaggy scaling hiện vật). – mark

1

Tôi đã gặp sự cố tương tự với chương trình C#/WPF.

Trong trường hợp của tôi, sự cố dường như đã gây ra do thiếu kích thước bên trong tệp ico. Kích thước nhỏ nhất mà tệp ico của ứng dụng của tôi là 64x64. Khi tôi đã thêm kích thước nhỏ hơn bên trong tệp đó, sự cố đã được giải quyết.

0

Cảm ơn các bạn rất nhiều vì điều này. Tôi có này để làm việc trong ứng dụng Wx của chúng tôi, nếu có ai muốn một số mã pre-nướng để thả vào ứng dụng Wx của họ vào đây là của tôi dưới đây:

#ifdef __WXMSW__ 
#include <Windows.h> 
#include <CommCtrl.h> 
#include <wx/msw/private.h> 
typedef int (WINAPI *func_LoadIconWithScaleDown)(HINSTANCE, LPCWSTR, int, int, HICON*); 
#endif 

void MainFrame::BindAppIcon() { 
#ifdef __WXMSW__ 
    wxDynamicLibrary comctl32("comctl32", wxDL_DEFAULT | wxDL_QUIET); 
    func_LoadIconWithScaleDown load_icon_scaled = reinterpret_cast<func_LoadIconWithScaleDown>(comctl32.GetSymbol("LoadIconWithScaleDown")); 
    int icon_set_count = 0; 

    HICON hIconLg; 
    if (load_icon_scaled && SUCCEEDED(load_icon_scaled(wxGetInstance(), _T("AAAAA_MAINICON"), ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON), &hIconLg))) { 
     ::SendMessage(GetHandle(), WM_SETICON, ICON_BIG, reinterpret_cast<LPARAM>(hIconLg)); 
     ++icon_set_count; 
    } 
    HICON hIconSm; 
    if (load_icon_scaled && SUCCEEDED(load_icon_scaled(wxGetInstance(), _T("AAAAA_MAINICON"), ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON), &hIconSm))) { 
     ::SendMessage(GetHandle(), WM_SETICON, ICON_SMALL, reinterpret_cast<LPARAM>(hIconSm)); 
     ++icon_set_count; 
    } 

    if (icon_set_count == 2) return; 
    // otherwise fall back to Wx method of setting icon 
#endif 
    wxIcon icon = wxXmlResource::Get()->LoadIcon(wxT("MainIcon")); 

    if (!icon.IsOk()) { 
     wxLogInfo(_("Main icon not found")); 
     icon = wxICON(wxvbam); 
    } 

    SetIcon(icon); 
} 

Dòng đầu tiên trong app.rc của bạn sau đó sẽ được một cái gì đó như thế này :

AAAAA_MAINICON ICON "icons/app.ico" 
Các vấn đề liên quan