На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Обратите внимание:
1. Прежде чем начать новую тему или отправить сообщение, убедитесь, что вы не нарушаете правил форума!
2. Обязательно воспользуйтесь поиском. Возможно, Ваш вопрос уже обсуждали. Полезные ссылки приведены ниже.
3. Темы с просьбой выполнить какую-либо работу за автора в этом разделе не обсуждаются.
4. Используйте теги [ code=cpp ] ...текст программы... [ /code ] для выделения текста программы подсветкой.
5. Помните, здесь телепатов нет. Старайтесь формулировать свой вопрос максимально грамотно и чётко: Как правильно задавать вопросы
6. Запрещено отвечать в темы месячной и более давности без веских на то причин.

Полезные ссылки:
user posted image FAQ Сайта (C++) user posted image FAQ Форума user posted image Наши Исходники user posted image Поиск по Разделу user posted image MSDN Library Online (Windows Driver Kit) user posted image Google

Ваше мнение о модераторах: user posted image B.V.
Модераторы: B.V.
  
> Меню
    Есть программа в которой рисуются прямоугольники. Расстояние до линий вычисляются по координатам. Если расстояние до линии прямоугольника меньше 4 пикселей при первом клике происходит ВЫДЕЛЕНИЕ прямоугольника, при клике по выделенному прямоугольнику происходит открытие окна СВОЙСТВА. Если второй клик вне области выделенного прямоугольника выделение ОТМЕНЯЕТСЯ. Все работает.

    В программах, как правило, принято аналогичные команды размещать в главном меню.
    У меня в меню есть пункт Properties (СВОЙСТВА) но при выделенном прямоугольнике клик по меню вместо открытия окна свойств отменяет выделение.

    Вопрос какой функцией определить раскрыто ли главное меню в текущий момент?
    Сообщение отредактировано: Mr.Brooks -
      Попробуй отслеживать инициализацию и деинициализацию меню. В оконную процедуру передаются сообщения вроде WM_INITMENU, WM_INITMENUPOPUP и WM_UNINITMENUPOPUP. Соответственно выключай и включай обработку кликов. Я тему не рыл, так что извини, если не сработает.
        Сделать глобальную переменную-флаг menuvisible, при обработке сообщений меню менять ее значение.
        А в функции, где я делаю клик учитывать эту переменную... такая мысль меня посещала. Наверное, как один из вариантов.

        Хотелось бы узнать, может кто-нибудь подскажет функцию, которая решит проблему без дополнительной глобальной переменной.
        Потому как у меня глобальных переменных сотни. А все книжки пишут что глобальные переменные - зло.

        Смотрю в сторону
        ExpandedWrap disabled
          int MenuItemFromPoint(HWND hWnd, HMENU hMenu, POINT ptScreen);

        похоже что она дает -1 если в заданной точке нет пункта меню.
          Цитата Mr.Brooks @
          Вопрос какой функцией определить раскрыто ли главное меню в текущий момент?

          Mr.Brooks, полагаю, что это вообще не нужно делать.
          -----
          Если в твоей программе обработчики разных событий хотят управлять
          одними и теми же объектами, значит они (обработчики) должны иметь
          возможность определить состояние этих объектов для правильного
          дальнейшего изменения этого состояния. Только и всего.
          -----
          Т.е. если из 2-х разных обработчиков показывается/скрывается окно "Свойства",
          каждый обработчик должен узнать - показано ли это окно или скрыто в данный момент.
          Тогда он может произвести правильные действия - скрыть/показать это окно.
          Итп итд.
          Можно посоветовать не делать слишком сложных зависимостей между разными обработчиками,
          если это возможно.
            Цитата Mr.Brooks @
            В программах, как правило, принято аналогичные команды размещать в главном меню.
            У меня в меню есть пункт Properties (СВОЙСТВА) но при выделенном прямоугольнике клик по меню вместо открытия окна свойств отменяет выделение.


            Скорее всего у тебя при выделении прямоугольника захватывается фокус мыши, SetCapture.
            Думаю, в данном случае это вообще не нужно.

            Иначе все сообщения мыши будут уходить в главное окно, в котором прямоугольники, до тех пор пока не будет вызвана ReleaseCapture.
              Для ясности приведу рисунки и вырезки из кода.
              (сразу прошу прощения возможно некоторые переменные не понятны)
              Прикреплённая картинка
              Прикреплённая картинка

              Прикреплённая картинка
              Прикреплённая картинка

              ExpandedWrap disabled
                // вырезки из кода
                 
                    case WM_COMMAND:
                        switch (LOWORD(wparam))
                        {        
                        case IDM_PROPERTIES:
                            DataElementProperties(hwnd);
                            break;
                        }
                    case WM_LBUTTONDOWN:
                        FormLButtonDown(hwnd);
                        return 0;
                    case WM_MOUSEMOVE:
                        FormMouseMove(hwnd, e::hstatusbar);
                        return 0;
                 
                //...
                 
                void FormLButtonDown(HWND hwnd)
                {
                    DataElementSelectCancel(hwnd);
                    DataElementSelectStop(hwnd);
                }
                 
                 
                void FormMouseMove(HWND hwnd, HWND hstatusbar)
                {
                    DataElementSelect(hwnd);
                }
                 
                //...
                 
                void DataElementProperties(HWND hwnd)
                {
                    int k;
                    k = e::projectstep;
                    if ((e::elementselectubound == 1) && (e::elementselectstop == e::elementselect[0]))
                    {
                            switch (e::element[k][e::elementselectstop].type)
                            {
                            case 0:
                                AssemblyCreateDlg(hwnd, e::hinst);
                                break;
                            }
                    }
                 
                }
                 
                void DataElementSelect(HWND hwnd)
                {
                    int i, j, k;
                    double d;
                    double x[3];
                    double y[3];
                    POINT ptcursor;
                    RECT rect;
                    k = e::projectstep;
                    GetCursorPos(&ptcursor);
                    GetWindowRect(hwnd, &rect);
                    x[0] = ptcursor.x - rect.left - 5;
                    y[0] = ptcursor.y - rect.top - 75;
                    e::elementselectubound = 0;
                    for (i=0; i<e::elementubound; i++)
                    {
                        for (j=0; j<e::element[k][i].schpointpairubound; j++)
                        {
                            x[1] = e::element[k][i].schpoint[0][0+2*j];
                            y[1] = e::element[k][i].schpoint[1][0+2*j];
                            x[2] = e::element[k][i].schpoint[0][1+2*j];
                            y[2] = e::element[k][i].schpoint[1][1+2*j];
                            d = DataElementSelectDist(x, y);
                            if ((d >= 0) && (d <= 3))
                            {
                                if (e::elementselectubound < 100)
                                {  
                                    e::elementselect[e::elementselectubound] = i;
                                    e::elementselectubound++;
                                    break;
                                }
                            }
                        }
                    }
                    RedrawWindow(hwnd, NULL, NULL, RDW_INTERNALPAINT);
                }
                 
                void DataElementSelectCancel(HWND hwnd)
                {
                    if ((e::elementselectubound != 1) || (e::elementselectstop != e::elementselect[0]))
                    {
                        e::elementselectstop = -1;
                    }
                    RedrawWindow(hwnd, NULL, NULL, RDW_INTERNALPAINT);
                }
                 
                double DataElementSelectDist(double x[3], double y[3])
                {
                    double a, b, c, d, len, l1, l2;
                    d = -1;
                    a = y[1] - y[2];
                    b = x[2] - x[1];
                    c = y[2] * x[1] - y[1] * x[2];
                    len = abs(sqrt(a * a + b * b));
                    l1 = abs(sqrt((y[1] - y[0]) * (y[1] - y[0]) + (x[1] - x[0]) * (x[1] - x[0])));
                    l2 = abs(sqrt((y[2] - y[0]) * (y[2] - y[0]) + (x[2] - x[0]) * (x[2] - x[0])));
                    if (len != 0)
                    {
                        d = abs((a * x[0] + b * y[0] + c) / len);
                        if ((l1 * l1) > (len * len + l2 * l2))
                        {
                            d = l2;
                        }
                        if ((l2 * l2) > (len * len + l1 * l1))
                        {
                            d = l1;
                        }
                    }
                    return d;
                }
                 
                void DataElementSelectStop(HWND hwnd)
                {
                    switch (e::elementselectubound)
                    {
                    case 0:
                        e::elementselectstop = -1;
                        break;
                    case 1:
                        if (e::elementselectstop == e::elementselect[0])
                        {
                            SendMessage(hwnd, WM_COMMAND, (WPARAM) IDM_PROPERTIES, NULL);
                        }
                        else
                        {
                            e::elementselectstop = e::elementselect[0];
                        }
                        break;
                    default:
                        SelectCreateDlg(hwnd, e::hinst);
                        break;
                    }
                    RedrawWindow(hwnd, NULL, NULL, RDW_INTERNALPAINT);
                }
                Цитата Mr.Brooks @
                Для ясности приведу рисунки и вырезки из кода.
                ---
                ..Получаем отмену выделения, что логично..

                Нет, это просто баг в программе.
                Обработчик пункта меню должен быть не тем же самым,
                что клик левой кнопкой мыши по окну.

                ExpandedWrap disabled
                     case WM_COMMAND:
                          switch (LOWORD(wparam))
                          {        
                          case IDM_PROPERTIES:
                              DataElementProperties(hwnd);
                              break;
                          }
                   
                   
                  // vvvvvvvvvv
                  //
                     return 0;
                  //
                  // ^^^^^^^^^^
                   
                      case WM_LBUTTONDOWN:
                          FormLButtonDown(hwnd);
                          return 0;
                Сообщение отредактировано: ЫукпШ -
                  комментарии

                  Правила которыми я руководствуюсь при написании программы:
                  1. Функции начинаются с названия модуля(файла) в котором они расположены.
                  2. Функции располагаются в алфавитном порядке.
                  3. Глобальные переменные в пространстве имен e::
                  4. Комментариев в программе не пишу принципиально. Любая функция или переменная должна иметь имя которое объясняет её назначение.
                  Ислючение самая первая строчка с названием файла. Если комментарии есть это временно для отладки.
                  ...

                  Теперь конкретно к приведенному коду
                  e::projectstep - переменная для реализации undo - redo текущий шаг = 0 пока в программе не меняется, зарезервирована.
                  e::elementselectubound - число выделенных элементов
                  e::elementselect[0] - массив список выделенных элементов
                  e::elementselectstop - текущий выделенный элемент
                  e::element[k][i].schpoint[0][0+2*j] - точки для рисования элементов
                  SelectCreateDlg - если выделено более 1 элемента (например они расположены друг на друге) появляется диалог селектор в котором нужно выбрать один из них.
                  AssemblyCreateDlg - диалог свойст элементов прямоугольников. ! его то и нужно отобразить при повторном клике по выделенному элементу.

                  Добавлено
                  Цитата

                  ExpandedWrap disabled
                    // vvvvvvvvvv
                    //
                      return 0;
                    //
                    // ^^^^^^^^^^



                  вообще-то есть у меня
                  return 0;
                  для case WM_COMMAND: switch очень длинный, потерялся return 0 при копировании, извиняюсь)
                  ExpandedWrap disabled
                        case WM_COMMAND:
                            switch (LOWORD(wparam))
                            {
                            case IDM_NEW:
                                FileNew(hwnd);
                                break;
                            case IDM_OPEN:
                                FileOpen(hwnd);
                                break;
                            case IDM_SAVE:
                                FileSave(hwnd);
                                break;
                            case IDM_SAVE_AS:
                                FileSaveAs(hwnd);
                                break;
                            case IDM_PRINT:
                                MessageBox(hwnd, "PRINT", "Message", MB_OK);
                                break;
                            case IDM_EXIT:
                                SendMessage(hwnd, WM_CLOSE, NULL, NULL);
                                break;
                            case IDM_UNDO:
                                MessageBox(hwnd, "UNDO", "Message", MB_OK);
                                break;
                            case IDM_REDO:
                                MessageBox(hwnd, "REDO", "Message", MB_OK);
                                break;
                            case IDM_CUT:
                                MessageBox(hwnd, "CUT", "Message", MB_OK);
                                break;
                            case IDM_COPY:
                                MessageBox(hwnd, "COPY", "Message", MB_OK);
                                break;
                            case IDM_PASTE:
                                MessageBox(hwnd, "PASTE", "Message", MB_OK);
                                break;
                            case IDM_DELETE:
                                MessageBox(hwnd, "DELETE", "Message", MB_OK);
                                break;
                            case IDM_PROPERTIES:
                                DataElementProperties(hwnd);
                                break;
                            case IDM_ASSEMBLY:
                                DataElementAdd(hwnd, 0);
                                break;
                     
                           // ...
                     
                            case IDM_TUTORIAL:
                                MessageBox(hwnd, "TUTORIAL", "Message", MB_OK);
                                break;
                            case IDM_ABOUT:
                                AboutCreateDlg(hwnd, e::hinst);
                                break;
                            }
                            return 0;
                  Сообщение отредактировано: Mr.Brooks -
                    Цитата Mr.Brooks @
                        case WM_LBUTTONDOWN:
                            FormLButtonDown(hwnd);
                            return 0;


                    У тебя это сообщение, SendMessage(hwnd, WM_COMMAND, (WPARAM) IDM_PROPERTIES, NULL);, вызывается при нажатии кнопки? Лучше бы при отпускании WM_LBUTTONUP. Возможно проблема в этом.
                      Разобрался )

                      Оказывается в функции DataElementProperties() которая должна отображать диалог свойств перепутались два понятия

                      1 выделенный элемент на котором пользователь кликнул.
                      (он остается выделенным независимо от движения мыши)

                      2 выделенный элемент текущий
                      (он зависит от координат мыши)

                      При выборе кликом мышью по выделенному элементу п1 совпадает с п2 так как координаты мыши и выделенного элемента совпадают.
                      При выборе через меню между п1 и п2 есть разница.

                      Нужно сделать вот так:
                      ExpandedWrap disabled
                        void DataElementProperties(HWND hwnd)
                        {
                            int k;
                            k = e::projectstep;
                            if (e::elementselectstop != -1)
                            {
                                switch (e::element[k][e::elementselectstop].type)
                                {
                                case 0:
                                    AssemblyCreateDlg(hwnd, e::hinst);
                                    break;
                                }
                            }
                        }


                      Всем спасибо. Вопрос решен.
                      Сообщение отредактировано: Mr.Brooks -
                      0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                      0 пользователей:


                      Рейтинг@Mail.ru
                      [ Script execution time: 0,0974 ]   [ 19 queries used ]   [ Generated: 16.04.24, 03:54 GMT ]