質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

4803閲覧

Win32APIでメニューバーを途中で違うものに替えたい

_volatile

総合スコア13

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2018/12/30 00:36

前提・実現したいこと

C++/Win32APIで
リソースに複数のメニューバーを用意し、何かしらのイベントでウィンドウのメニューバーを切り替えられるようにしたいです。
例として、左クリックした場合は日本語のメニューバー、右クリックした場合は英語のメニューバーに切り替わるようにします。

発生している問題・エラーメッセージ

関数SetClassLongPtrが上手く機能せず、メニューバーが切り替わりません。

該当のソースコード

C++

1// winmain.cpp 2#define UNICODE 3#define _UNICODE 4#define MAX_LOADSTRING 100 5 6#include <tchar.h> 7#include <windows.h> 8#include "resource.h" 9 10namespace 11{ 12// Global Variables: 13HINSTANCE hInst; // current instance 14TCHAR szTitle[MAX_LOADSTRING]; // The title bar text 15TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name 16} // namespace 17 18// Forward declarations of functions included in this code module: 19ATOM MyRegisterClass(HINSTANCE hInstance); 20BOOL InitInstance(HINSTANCE, int); 21LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); 22INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); 23bool anotherInstance(); 24 25int WINAPI _tWinMain(HINSTANCE hInstance, 26 HINSTANCE hPrevInstance, 27 LPTSTR lpCmdLine, 28 int nCmdShow) 29{ 30 UNREFERENCED_PARAMETER(hPrevInstance); 31 UNREFERENCED_PARAMETER(lpCmdLine); 32 33 // Initialize global strings 34 LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); 35 LoadString(hInstance, IDC_APP, szWindowClass, MAX_LOADSTRING); 36 MyRegisterClass(hInstance); 37 38 // Perform application initialization: 39 if (!InitInstance(hInstance, nCmdShow)) 40 { 41 return FALSE; 42 } 43 44 MSG msg; 45 // Main message loop: 46 while (GetMessage(&msg, nullptr, 0, 0)) 47 { 48 TranslateMessage(&msg); 49 DispatchMessage(&msg); 50 } 51 return static_cast<int>(msg.wParam); 52} 53 54// FUNCTION: MyRegisterClass() 55// PURPOSE: Registers the window class. 56ATOM MyRegisterClass(HINSTANCE hInstance) 57{ 58 WNDCLASSEX wcex; 59 60 wcex.cbSize = sizeof(WNDCLASSEX); 61 62 wcex.style = CS_HREDRAW | CS_VREDRAW; 63 wcex.lpfnWndProc = WndProc; 64 wcex.cbClsExtra = 0; 65 wcex.cbWndExtra = 0; 66 wcex.hInstance = hInstance; 67 wcex.hIcon = nullptr; 68 wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); 69 wcex.hbrBackground = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH)); 70 wcex.lpszMenuName = MAKEINTRESOURCE(IDC_MENU_JPN); 71 wcex.lpszClassName = szWindowClass; 72 wcex.hIconSm = nullptr; 73 74 return RegisterClassEx(&wcex); 75} 76 77// FUNCTION: InitInstance(HINSTANCE, int) 78// PURPOSE: Saves instance handle and creates main window 79BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) 80{ 81 hInst = hInstance; // Store instance handle in our global variable 82 83 HWND hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, 84 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr); 85 86 if (!hWnd) 87 { 88 return FALSE; 89 } 90 91 ShowWindow(hWnd, nCmdShow); 92 UpdateWindow(hWnd); 93 94 return TRUE; 95} 96 97// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM) 98// PURPOSE: Processes messages for the main window. 99LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 100{ 101 switch (message) 102 { 103 case WM_COMMAND: 104 switch (LOWORD(wParam)) 105 { 106 case IDM_EXIT: 107 DestroyWindow(hWnd); 108 break; 109 case IDM_ABOUT: 110 MessageBox(nullptr, TEXT("Version x.x.x"), TEXT(""), MB_OK); 111 break; 112 } 113 break; 114 case WM_LBUTTONDOWN: 115 SetClassLongPtr(hWnd, GCLP_MENUNAME, (LONG_PTR)IDC_MENU_JPN); //日本語用のメニューバーにする 116 break; 117 case WM_RBUTTONDOWN: 118 SetClassLongPtr(hWnd, GCLP_MENUNAME, (LONG_PTR) nullptr); //Set English Menubar 119 break; 120 case WM_DESTROY: 121 PostQuitMessage(0); 122 break; 123 default: 124 return DefWindowProc(hWnd, message, wParam, lParam); 125 } 126 return 0; 127}

C++

1//resource.h 2#define IDS_APP_TITLE 100 3#define IDC_APP 101 4 5#define IDC_MENU_JPN 110 6#define IDC_MENU_ENG 111 7 8#define IDM_EXIT 120 9#define IDM_ABOUT 121
//resource.rc #pragma code_page(65001) #include "resource.h" STRINGTABLE BEGIN IDS_APP_TITLE "Sample Windows Application" IDC_APP "SAMPLE" END IDC_MENU_JPN MENU BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "終了(&X)", IDM_EXIT END POPUP "ヘルプ(&H)" BEGIN MENUITEM "情報(&A)", IDM_ABOUT END END IDC_MENU_ENG MENU BEGIN POPUP "&File" BEGIN MENUITEM "E&xit", IDM_EXIT END POPUP "&Help" BEGIN MENUITEM "&About", IDM_ABOUT END END

試したこと

コンパイルは

windres resource.rc resource.o clang++ winmain.cpp resource.o -Wall -std=c++17 -mwindows -municode

SetClassLongPtr関数の実引数を色々書き換えましたが、コンパイルエラー、あるいは何も起きないです…。
どのようにすれば実現できるか分かる方助言をお願いしますm(__)m

補足情報(FW/ツールのバージョンなど)

Windows10

//clang -v clang version 7.0.1 (tags/RELEASE_701/final) Target: x86_64-w64-windows-gnu Thread model: posix InstalledDir: C:\msys64\mingw64\bin

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

メニューを動的に変更するには SetMenu APIを使います。流れ的には、LoadMenuでメニューをロードしておき、SetMenuでセット。必要無くなったらDestroyMenuで破棄、です。

ウィンドウプロシージャにおいて、WM_CREATEメッセージ受信時にLoadMenuしておいて、何らかのイベントとする為にマウス左ボタンクリックであるWM_LBUTTONDOWN時にSetMenuでメニューを切り替え、WM_DESTROY時に破棄する例です。

C

1LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 2{ 3 static bool fToggle = false; 4 static HMENU hMenuEng = NULL; 5 static HMENU hMenuJpn = NULL; 6 7 switch (message) 8 { 9 case WM_CREATE: 10 { 11 // あらかじめ必要なメニューをロードしておく 12 hMenuJpn = LoadMenu(hInst, (LPCTSTR)MAKEINTRESOURCE(IDC_MENU_JPN)); 13 hMenuEng = LoadMenu(hInst, (LPCTSTR)MAKEINTRESOURCE(IDC_MENU_ENG)); 14 return DefWindowProc(hWnd, message, wParam, lParam); 15 } 16 break; 17 18 case WM_LBUTTONDOWN: 19 { 20 // マウス左クリックで交互に入れ替えるテスト 21 fToggle = !fToggle; // フラグ反転 22 HMENU hMenu = fToggle ? hMenuEng : hMenuJpn; 23 SetMenu(hWnd, hMenu); 24 return DefWindowProc(hWnd, message, wParam, lParam); 25 } 26 break; 27 28 case WM_DESTROY: 29 { 30 // Window破棄時にメニューも破棄 31 if (hMenuJpn != NULL) { 32 DestroyMenu(hMenuJpn); 33 } 34 if (hMenuEng != NULL) { 35 DestroyMenu(hMenuEng); 36 } 37 38 PostQuitMessage(0); 39 return 0; 40 } 41 break; 42 43 case WM_COMMAND: 44 { 45 46...続く

RegisterClassExで構造体メンバーlpszMenuNameにあらかじめメニューをセットしていた場合、厳密には自力で破棄する必要があることになるので注意してください。

SetMenuのリファレンスより引用

既にメニューが割り当てられているウィンドウに対して SetMenu 関数を呼び出すと、この関数は既存のメニューを置き換えますが、破棄しません。以前のメニューを破棄するには、アプリケーションは DestroyMenu 関数を呼び出すべきです。

尚、Visual Studo 2017で確認したもので、clang環境でのビルドは試していませんのでご了承ください。

投稿2018/12/30 01:51

dodox86

総合スコア9183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

_volatile

2018/12/30 14:53

ありがとうございます。 無事解決いたしました。
guest

0

動的に変える場合はLoadMenu, SetMenuっていうそのまんまのAPIがあるんでこちらを使ってください。

C++

1SetMenu(hWnd, LoadMenu(hInst, MAKEINTRESOURCE(IDC_MENU_JPN);

投稿2018/12/30 01:52

toki_td

総合スコア2850

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問