Отобразите подсказку ToolTip на отключенном пункте меню всплывающего меню

Из объявленных вами переменных вы инициализировали (пользовательский ввод) только p1 и p2; остальные P,p,R,r,S,s из них все еще неинициализированы и имеют мусорное значение.

Далее в программе вы сравниваете их с p1 и p2. Это неопределенное поведение . Поэтому инициализируйте их перед выполнением операции сравнения с ними.


Просто для разъяснения; P,p,R,r,S,s называются идентификаторами, и вам необходимо значение float, чтобы присвоить их (поскольку они имеют тип float).

Скорее всего, вам нужно char вместо float.

char  p1, p2;
std::cin >>p1 >> p2;

для сравнения вы должны сделать

if (std::to_upper(p1) == 'P' && std::to_upper(p2) == 'R')
    ^^^^^^^^^^^^^^       ^^^^   ^^^^^^^^^^^^^^       ^^^^

Обратите внимание, что std :: toupper предназначен для преобразования символа в верхний регистр, что уменьшит количество проверок, что вы сделали.

Хотя вам нужно проверить, являются ли p1 и p2 какие-либо из 'P', 'R' или 'S', равны ли они.

Используя троичный оператор , можно написать один код лайнера следующим образом:

#include 
#include    // std::toupper

int main()
{
    std::cout << "Input Player 1 and Player 2 Choices\n";
    char p1, p2; std::cin >> p1 >> p2;

    p1 = std::toupper(p1); // convert to upper case
    p2 = std::toupper(p2); // convert to upper case

    std::cout << (
        (p1 == p2 && (p1 == 'P' || p1 == 'R' || p1 == 'S')) ? "tie\n" 
        : (p1 == 'P' && p2 == 'R') || (p1 == 'R' && p2 == 'P') ? "Paper covers rock!\n"
        : (p1 == 'S' && p2 == 'R') || (p1 == 'R' && p2 == 'S') ? "Rock breaks scissors!\n"
        : (p1 == 'S' && p2 == 'P') || (p1 == 'P' && p2 == 'S') ? "Scissors cut paper!\n"
        : "Wrong input!\n"
        );

    return 0;
}

6
задан Community 23 May 2017 в 12:00
поделиться

2 ответа

WM_MENUSELECT действительно обрабатывается для пунктов меню во всплывающих меню также, но не окнами proc формы, содержащей (раскрывающееся) меню, но невидимым окном помощника, созданным Меню. PopupList. К счастью Вы можете (по крайней мере, под Delphi 5), достигают этот HWND с помощью Меню. PopupList. Окно.

Теперь можно использовать старомодный способ разделить окно на подклассы, как описано, например, в этой статье CodeGear, обработать WM_MENUSELECT также для всплывающих меню. HWND будет допустим от того, после того, как первый TPopupMenu будет создан к тому, прежде чем последний объект TPopupMenu будет уничтожен.

Быстрый тест с демонстрационным приложением в связанной статье в вопросе должен показать, собирается ли это работать.

Править: Это действительно работает. Я изменил связанный пример для показа подсказок также для всплывающего меню. Вот шаги:

Добавьте обработчик для OnDestroy, членскую переменную для старого окна proc и метода для нового окна proc к форме:

TForm1 = class(TForm)
  ...
  procedure FormCreate(Sender: TObject);
  procedure FormDestroy(Sender: TObject);
  procedure ApplicationEvents1Hint(Sender: TObject);
private
  miHint : TMenuItemHint;
  fOldWndProc: TFarProc;
  procedure WMMenuSelect(var Msg: TWMMenuSelect); message WM_MENUSELECT;
  procedure PopupListWndProc(var AMsg: TMessage);
end;

Измените обработчик OnCreate формы, чтобы разделить скрытое окно PopupList на подклассы и реализовать надлежащее восстановление окна proc в обработчике OnDestroy:

procedure TForm1.FormCreate(Sender: TObject);
var
  NewWndProc: TFarProc;
begin
  miHint := TMenuItemHint.Create(self);

  NewWndProc := MakeObjectInstance(PopupListWndProc);
  fOldWndProc := TFarProc(SetWindowLong(Menus.PopupList.Window, GWL_WNDPROC,
    integer(NewWndProc)));
end;

procedure TForm1.FormDestroy(Sender: TObject);
var
  NewWndProc: TFarProc;
begin
  NewWndProc := TFarProc(SetWindowLong(Menus.PopupList.Window, GWL_WNDPROC,
    integer(fOldWndProc)));
  FreeObjectInstance(NewWndProc);
end;

Реализуйте разделенное на подклассы окно proc:

procedure TForm1.PopupListWndProc(var AMsg: TMessage);

  function FindItemForCommand(APopupMenu: TPopupMenu;
    const AMenuMsg: TWMMenuSelect): TMenuItem;
  var
    SubMenu: HMENU;
  begin
    Assert(APopupMenu <> nil);
    // menuitem
    Result := APopupMenu.FindItem(AMenuMsg.IDItem, fkCommand);
    if Result = nil then begin
      // submenu
      SubMenu := GetSubMenu(AMenuMsg.Menu, AMenuMsg.IDItem);
      if SubMenu <> 0 then
        Result := APopupMenu.FindItem(SubMenu, fkHandle);
    end;
  end;

var
  Msg: TWMMenuSelect;
  menuItem: TMenuItem;
  MenuIndex: integer;
begin
  AMsg.Result := CallWindowProc(fOldWndProc, Menus.PopupList.Window,
    AMsg.Msg, AMsg.WParam, AMsg.LParam);
  if AMsg.Msg = WM_MENUSELECT then begin
    menuItem := nil;
    Msg := TWMMenuSelect(AMsg);
    if (Msg.MenuFlag <> $FFFF) or (Msg.IDItem <> 0) then begin
      for MenuIndex := 0 to PopupList.Count - 1 do begin
        menuItem := FindItemForCommand(PopupList.Items[MenuIndex], Msg);
        if menuItem <> nil then
          break;
      end;
    end;
    miHint.DoActivateHint(menuItem);
  end;
end;

Это сделано для всех всплывающих меню в цикле, пока первый объект соответствия или подменю не найден.

6
ответ дан 10 December 2019 в 02:54
поделиться

Не уверенный, если это помогает, но я создал свое собственное многострочное окно подсказки (для Delphi7), чтобы смочь показать больше затем всего одну строку текста. Это - открытый исходный код, и можно найти его здесь.

Существует включенный показ некоторой работы его на правильном местоположении на экране, но Вы имеете полный контроль над ним.

3
ответ дан 10 December 2019 в 02:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: