Перейти к содержанию
Fire Monkey от А до Я

Вадим Смоленский

Пользователи
  • Постов

    222
  • Зарегистрирован

  • Посещение

  • Победитель дней

    5

Сообщения, опубликованные Вадим Смоленский

  1. Проблема обозначена в заголовке. Подробнее: при дефолтных установках TFDConnection.ResourceOption  (включенных EscapeExpand, MacroCreate, MacroExpand, ParamCreate, ParamExpand) функция Locate возвращает False. При отключении этих параметров Locate падает с сообщением "Unrecognized token {"

    Вынужден вместо Locate использовать Filter, очень сильно проигрывая в скорости. Хотелось бы все-таки понять, в чем тут дело.

     

  2. Наверное, детский вопрос задам, и все-таки. Вдруг обнаружил, что в моем проекте никакие блоки try...except не срабатывают. Видимо, дело в каких-то настройках — но в каких именно? Иду в Options => Debugger Options => Embarcadero Debuggers => Native OS Exceptions, пробую там менять установки, толку никакого. Более того — пытаюсь искусственно спровоцировать падение делением на ноль — и вообще никакого падения не происходит, деление на ноль дает ноль! Такая же примерно ерунда с попыткой устроить переполнение.

    Ткните меня в причину носом кто-нибудь, пожалуйста.

    UPD  Через два дня хаотичных экспериментов с настройками всё прочихалось, и exceptions благополучно работают. В чем было дело, так и не понял.

  3. У одного из тестировщиков, под Windows, моя сборка регулярно падает с такой ошибкой:

    Cannot create rendering target for 'TCanvas2D2'

    В свое время я и сам с этим сталкивался. У себя поборол уменьшением размеров всех TBitmap ниже некоторого предела. Померили максимальный размер TBitmap на компьютере тестировщика функцией TCanvasManager.DefaultCanvas.GetAttribute(TCanvasAttribute.MaxBitmapSize), получилось 8192. На моем компьютере столько же — однако у него падает, а у меня нет. Причем падает не при отрисовке изображения, а уже потом, при каких-то случайных действиях, с отрисовкой не связанных. Всякий раз непредсказуемо. Но он заметил, что если на форму выведено больше крупных изображений, то падает быстрее.

    Как это трактовать и что с этим делать?

  4. 1 час назад, POV сказал:

    Возможно, я это имел в виду.
    http://docwiki.embarcadero.com/Libraries/Rio/en/FMX.Types.TPixelFormat

    Да, я это видел, конечно. Но очень плохо растолковано. Какое из этих значений соответствует монохромному изображению? L, может быть? И как именно этот формат выставлять? У TBitmap это свойство Read-only.

  5. Имею в своем проекте огромный невидимый TImage, из которого при необходимости вырезаются те или иные кусочки и показываются пользователям. Так оказалось сделать удобнее, чем хранить эти кусочки в БД. Изображение монохромное, из черных и белых пикселей, цвета не нужны. Я полагал, что достаточно загрузить в TImage.MultiResBitmap монохромный файл, чтобы битмэп и трактовался программой как монохромный. Но сейчас проверил это функцией PixelFormatToString - и увидел, что пиксельный формат имеет значение BGRA. Похоже, под цвета по-прежнему выделяются ресурсы, которые можно было бы сэкономить. Возникают следующие вопросы:

    1. Действительно ли PixelFormat=BGRA означает, что мой TBitmap не является монохромным и занимает в памяти в разы больше места?

    2. Если да, то есть ли способ сделать его монохромным?

  6. Узнал, что в UWP API включены средства для получения уникального идентификатора компьютера. Это юнит Windows.System.Profile, класс HardwareIdentification, метод getPackageSpecificToken. Существуют ли способы обратиться к этим средствам из Delphi?

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

  7. Немножко улучшил свой вариант. Теперь вообще как часы всё заработало.

    var TheFormIsMinimized: Boolean = False;
        TheFormWasMaximized: Boolean = False;
    
    function NewWndProc(Wnd: HWND; Msg: UINT; WParam: WPARAM; LParam: LPARAM): LRESULT; stdcall;
    begin
     if (Msg = WM_SHOWWINDOW) and (LParam = SW_PARENTCLOSING) and (not TheFormIsMinimized) then
         begin
          TheFormIsMinimized := True;
          TheFormWasMaximized := (MainForm.WindowState=TWindowState.wsMaximized);
          SendMessage(FormToHWND(MainForm), WM_SYSCOMMAND, SC_MINIMIZE, 0);
          MainFormp.WindowState := TWindowState.wsMinimized;
         end else
     if (Msg = WM_SHOWWINDOW) and (LParam = SW_PARENTOPENING) and (TheFormIsMinimized) then 
         begin
          TheFormIsMinimized := False;
          SendMessage(FormToHWND(MainForm), WM_SYSCOMMAND, SC_RESTORE, 0);
          if TheFormWasMaximized
             then MainForm.WindowState := TWindowState.wsMaximized
             else MainForm.WindowState := TWindowState.wsNormal;
         end
      else Result:=CallWindowProc(OldWndProc, Wnd, Msg, WParam, LParam);
    end;

    Единственный недостаток: при восстановлении из wsMinimized в wsMaximized на долю секунды окно фиксируется как wsNormal. Но это, в общем-то, не страшно.

  8. 37 минут назад, mmover сказал:

    Вот такая конструкция получилась

    Да, я сейчас тоже попробовал сделать через перехват, только попроще. Работает. Вот как выглядит функция:

    function NewWndProc(Wnd: HWND; Msg: UINT; WParam: WPARAM; LParam: LPARAM): LRESULT; stdcall;
    begin
     if (Msg = WM_SHOWWINDOW) and (LParam = SW_PARENTCLOSING) then 
         begin
          SendMessage(FormToHWND(MainForm), WM_SYSCOMMAND, SC_MINIMIZE, 0);
          Application.ProcessMessages;
          MainForm.WindowState := TWindowState.wsMinimized;
         end
      else Result := CallWindowProc(OldWndProc, Wnd, Msg, WParam, LParam);
    end;

    ProcessMessages пришлось вставить из-за того, что без этого приложение перед сворачиванием на долю секунды становилось черным. Наверное, можно сделать изящнее - в вашем примере, как я понял, TThread помогает. Но все-таки оно работает, и это, безусловно, изящнее, чем курочить FMX.Platform.Win и таскать его туда-сюда.

  9. В 19.11.2018 в 12:40, sargon сказал:

    С такими изменениями вроде все работает корректно

    Воспроизвел изменения у себя - и увы! Не только сворачивание не стало работать правильно, но даже перетащить окно теперь не получается. Что-то с этим кодом всё равно не так...

    Кстати, попробовал перехватить событие WM_SYSCOMMAND и обнаружил, что оно происходит только при щелчке по кнопке Minimize в шапке окна, а при щелчке по иконке в трее уже не происходит. Не то мы ловим.

  10. 4 часа назад, dnekrasov сказал:

    Попробуйте ещё так сделать

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

    Очень и очень признателен. Желаю всяческих благ - и отдельно успехов дочери на поприще японистики!

  11. 1 час назад, dnekrasov сказал:

    Сложно что-то посоветовать, когда не можешь повторить ошибку...

    Вынес всё, касающееся этой проблемы, в отдельный проект. У меня продолжает падать и в таком виде. Не поленитесь проверить, упадет ли у вас.

    Файл FMX.Platform.Win.pas я в свое время чуть изменил из-за каких-то проблем (сходу и не вспомню, каких), и с тех пор держу его в одной папке с проектом. Может, с ним что не так?

    ImeProject.zip

  12. 4 минуты назад, dnekrasov сказал:

    Не понял что такое LookUp.Handle

    LookUp - это название моей формы, которое я забыл поменять на MyForm. Но можно и без него, конечно. Однако же, у меня и в таком виде всё равно валится. Что еще тут стоит проверить?..

  13. 3 часа назад, dnekrasov сказал:

    Именно перенос в CreateHandle и решает проблему

    Да, действительно. Теперь управление в нужные моменты передается WMIMENotify. Спасибо еще раз. Однако, к сожалению, это пока не помогло мне решить исходной проблемы. Не знаю, уместно ли будет изложить эту проблему здесь - все-таки она связана с процедурами IME для ввода японского текста; с этим мало кто сталкивается. И тем не менее: когда включена японская локаль и выбран ввод хираганой (слоговой азбукой), то при печатании в TEdit на экран автоматически выдается маленькое окошко (candidate window) со списком иероглифов или слов, которые могли бы соответствовать набранному чтению. Пользователь может выбрать одного из этих кандидатов. Проблема в том, что когда включено экранное масштабирование (скажем, 125%), candidate window выскакивает не строго под TEdit, как должно, а левее и выше. Похоже, это недоработка FireMonkey - при передаче координат курсора ввода масштабирование не учитывается. Я хотел наладить перехват выдачи candidate window с присвоением ему других координат. Сам перехват теперь получается (при вызове candidate window выдается сообщение WM_IME_NOTIFY с WParam=IMN_SETCANDIDATEPOS). А вот так выглядит у меня обработка этого перехвата в рекомендованной вами процедуре:

    uses imm;
    
    procedure TMyForm.WMIMENotify(var Msg: TMessage);
    var Imc: HIMC;
        ImeCandidateFormProperties: TCandidateForm;
    begin
     Imc:=ImmGetContext(FMXHandleToHWND(LookUp.Handle));
     ImmGetCandidateWindow(Imc,0,@ImeCandidateFormProperties);
     ImeCandidateFormProperties.dwStyle:=CFS_CANDIDATEPOS;
     ImeCandidateFormProperties.ptCurrentPos.X:=100;
     ImeCandidateFormProperties.ptCurrentPos.Y:=100;        
     ImmSetCandidateWindow(Imc,@ImeCandidateFormProperties);
     ImmReleaseContext(FMXHandleToHWND(LookUp.Handle),Imc);
    end;

    Сколь могу судить, ImmGetCandidateWindow успешно считывает данные о candidate window. Но заменить их на исправленные уже не выходит, при вызове ImmSetCandidateWindow происходит переполнение стека.

    Документация о ImmSetCandidateWindow лежит здесь. Опять же: трудно надеяться, что вы сможете помочь - но вдруг?

  14. 20 минут назад, dnekrasov сказал:

    За счет строчки

    Попробовал повторить у себя. Получилось странно. Во время запуска приложения управление множество раз переходит в NewWndProc, в том числе и дважды с сообщением WM_IME_NOTIFY. Но как только главное окно появилось на экране - больше ни разу, ни с какими сообщениями вообще.

    Что-то где-то недокручено, такое впечатление...

  15. 5 часов назад, kami сказал:

    Нужно перехватывать в рамках своего окна / приложения / системы вцелом ?

    Можно считать, что в рамках окна.

     

    2 часа назад, dnekrasov сказал:

    Делаем как обычно, если надо переопределить какое-то событие окна

    Спасибо, Некрасов-сан. Выглядит интригующе. Но я не могу понять, как управление перейдет в процедуру WMIMENotify. Она ведь у вас вообще нигде не вызывается.

    P.S. А, понял. Она вызывается в FMX.Platform.Win:

              WM_IME_NOTIFY:
                begin
                  Result := WMImeNotify(LForm, hwnd, uMsg, wParam, lParam);
                end;

     

  16. Для задач, связанных с вводом японского текста, мне нужно научиться перехватывать системное сообщение WM_IME_NOTIFY. Насколько могу судить, в FireMonkey эти вещи делаются (если вообще делаются) принципиально иначе, нежели в VCL. Конкретного ничего не нагуглил. Не поможет ли кто?

  17. Спасибо. Вижу, что не у одного меня такая проблема. Библиотека по ссылке - это что-то дотнетовское, едва ли подойдет. Придется, видимо, подождать до релиза 10.3.

    Хотя вот еще нашелся интересный компонент. Платный, но стоит попробовать, думаю.

  18. В многомесячной борьбе с Microsoft Store за размещение у них своего Windows-приложения я продвинулся настолько, что вплотную подошел к организации взимания денег с покупателей посредством механизма add-ons (in-app purchases). Но здесь меня ждала очередная засада. Необходимые программные инструменты, главным из которых считается класс StoreContext, лежат в пространстве имен Windows.Services.Store; файлы с такими именами (windows.services.store.h и windows.services.store.idl) в Windows 10 действительно находятся; но в Delphi я не могу найти юнита с чем-то подобным. Хотя на одном форуме видел утверждение годичной давности, что в релизе 10.2 Tokyo это уже есть.

    Не может ли кто-нибудь пролить свет? Не там ищу? Все-таки еще не добавили? Или, может, это появилось лишь в самой последней сборке 10.2.3? У меня стоит 10.2.2.

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

  19. В феврале я сетовал, что мое Windows-приложение не хочет нормально запускаться в Linux под Wine 3.0. Но время идет, вышел Wine 3.6 - и теперь один из тестировщиков радостно сообщил, что всё заработало, за вычетом одного досадного момента. А именно: приложение способно сохранять фокус ввода лишь долю секунды, потом теряет. Соответственно, невозможно ничего ввести в текстовые боксы, разве только одну-две буквы. Можно щелкнуть по заголовку приложения, оно опять получит фокус - и через мгновение снова потеряет. Куда именно при этом переходит фокус, непонятно. Тестировщик утверждает, что только мое приложение ведет себя так, все остальные работают нормально.

    Нет ли у кого-нибудь идей? Что нужно проверить?

  20. 6 часов назад, IVGSoft сказал:

    Пытаюсь исправить.

    Хорошо, если получится исправить. В моем-то проекте гифки самые простые, без прозрачности и черезстрочности, так что я ничего такого и не заметил.

  21. 17 часов назад, kami сказал:

    Что может быть непонятно во фразе non-zero value из первоисточника?

    Да нет, всё понятно теперь. Я просто упустил из вида, что внутри функции CallNextHookEx еще много всякого разного может происходить и ее выходное значение в данном случае - не самое главное. Кстати, в отладчике посмотрел - оно в штатном режиме действительно получается нулевым.

    Так что теперь в тех случаях, когда нажатие клавиши точно обработано моим приложением и я больше не хочу от него никаких сюрпризов, просто присваиваю Result:=1. Всё работает, как часы. Огромное спасибо!

  22. 4 часа назад, kami сказал:

    Или же - вызываете, но Result возвращаете <>0.

    Это непонятно. Какой именно <>0? Любой кроме ноля? А если, как советуют, присвоить CallNextHookEx(CurrentHook, nCode, wParam, lparam), то это всегда будет ноль, что ли?

  23. 1 час назад, kami сказал:

    Внимательно читаем раздел Result

    Такого раздела там нет. Вы, видимо, имели в виду раздел "Return value". В частности, там сказано, что CallNextHookEx нужно вызывать в том случае, если (цитирую) the hook procedure did not process the message. То есть, насколько я понял, если моя процедура FormKeyDown установила Key:=0, то это можно трактовать в том ключе, что message обработан, и тогда CallNextHookEx вызывать необязательно. Так или не так?

    Ваши рекомендации меня запутали: строчку убирать не надо, я должен вызвать следующий хук, но лучше этот вызов пропустить. Как это всё трактовать в терминах конкретных действий?

    1 час назад, kami сказал:

    Тот же WH_KEYBOARD: система будет вызывать последовательно все KeyboardProc в порядке (емнип), обратном времени установки хука.

    Я так и не смог понять разницы между WH_KEYBOARD_LL и WH_KEYBOARD. Мне казалось, что лишь первый вариант относится ко всей системе целиком и проверяется всеми приложениями, где есть хук, в то время как второй ограничен лишь одним-единственным приложением. Всё сложнее?

×
×
  • Создать...