1 (2020-12-08 15:26:15 отредактировано swerg)

Тема: Создание таблиц из скриптов на нужной вкладке

Берём [url=https://quik2dde.ru/viewtopic.php?id=78]свежую версию библиотеки w32[/url].
Для выбора нужной вкладки, на которой требуется создать таблицу из скрипта, используем функции TabCtrl_*

Ниже пример использования разных возможностей работы с вкладками.
Обратите внимание, что основной код по переключения / получению информации с вкладок сделан под условием
if hTabWnd > 0 then
В этом тестовом скрипте всё удалось уложить под один if, возможно в реальном скрипте придётся добавлять такую проверку для несколько раз. Хотя, если такую проверку не сделать - ничего страшного не случится, просто не получим параметры вкладок / не сменим текущую вкладку. Но терминал точно не упадёт при отсутствии такой проверки.

w32 = require("w32")

-- Возвращает handle главного окна QUIK или 0 при ошибке
-- Если запущено несколько терминалов - выбирается тот QUIK, из которого запущен наш скрипт
function GetQuikMainWindowHandle()
    local hQuikWnd = 0
    while true do
        hQuikWnd = w32.FindWindowEx(0, hQuikWnd, "InfoClass", "")
        if hQuikWnd == 0 then
            break
        end
        local t,WinProcId = w32.GetWindowThreadProcessId(hQuikWnd)
        if WinProcId == w32.GetCurrentProcessId() then
            break
        end
    end

    return hQuikWnd
end

-- Тестовая функция создания пользовательского окна с таблицей
function CreateTableWindow(caption)
    local t_id = AllocTable()   
    AddColumn(t_id, 0, "1", true, QTABLE_INT_TYPE, 15)
    AddColumn(t_id, 1, "2", true, QTABLE_INT_TYPE, 15)
    local t = CreateWindow(t_id)
    SetWindowCaption(t_id, caption)
    InsertRow(t_id, -1)
    SetCell(t_id, 1, 1, "<<" .. caption .. ">>")
end

-- Основной код

hQuikWnd = GetQuikMainWindowHandle()

-- получим handle окна вкладок, далее все операции по переключению вкладок будем совершать с этим окном
hTabWnd = 0
if hQuikWnd > 0 then
    hTabWnd = w32.FindWindowEx(hQuikWnd, 0, "SysTabControl32", "")
    if hTabWnd ~= 0 and not w32.IsWindowVisible(hTabWnd) then
        -- Если окно вкладок найдено, но отображение вкладок отключено - сбросим в 0
        hTabWnd = 0
    end
end

if hTabWnd > 0 then
    -- Если вкладки в терминале отображаются
    -- Сохраним индекс текущей активной вкладки
    local prevIdx = w32.TabCtrl_GetCurFocus(hTabWnd)

    -- Определим и выведем через message() наименование активной вкладки на момент старта
    -- (индекс активной вкладки сохранён ранее, так что здесь получаем / отображаем имя просто так)
    -- w32.TabCtrl_GetItemText() вызываем только с 1 параметром, т.к. нас интересует имя активной вкладки
    local activeTabName = w32.TabCtrl_GetItemText(hTabWnd)
    if activeTabName then
        -- т.к. явно проверили, что имя вкладки получить удалось (оно не nil)
        -- просто отображаем его без tostring()
        message("Активна вкладка: " .. activeTabName)
    end

    -- Получим индекс вкладки с именем "Графики" (если такая существует)
    local idxGr = w32.TabCtrl_GetItemIndexByText(hTabWnd, "Графики")
    if idxGr >= 0 then
        -- Если вкладка "Графики" найдена
        -- переключимся на неё и создадим таблицу на ней, получив имя
        w32.TabCtrl_SetCurFocus(hTabWnd, idxGr)
        -- Получим название текущей активной вкладки (только что на нее переключились)
        local txt = w32.TabCtrl_GetItemText(hTabWnd)
        -- Используем tostring(), т.к. TabCtrl_GetItemText при ошибке возвращает nil
        CreateTableWindow("Вкладка '" .. tostring(txt) .. "'")
    end

    -- Получим общее количество вкладок
    cnt = w32.TabCtrl_GetItemCount(hTabWnd)
    for i = 0, cnt-1 do
        -- Переключаемся поочередно на каждую вкладку и создаем таблицу с именем вкладки
        w32.TabCtrl_SetCurFocus(hTabWnd, i)
        -- Получим название вкладки
        -- т.к. получаем название текущей активной вкладки (только что на нее переключились),
        -- то второй параметр можно не указывать; но здесь оставлен второй параметр для тестов
        local txt = w32.TabCtrl_GetItemText(hTabWnd, i)
        -- Используем tostring(), т.к. TabCtrl_GetItemText при ошибке возвращает nil
        CreateTableWindow(tostring(txt))
    end

    -- Переключимся назад на исходную вкладку
    w32.TabCtrl_SetCurFocus(hTabWnd, prevIdx)
else
    -- Если вкладки в терминале не отображаются
    CreateTableWindow("Вкладки отключены")
end

2

Re: Создание таблиц из скриптов на нужной вкладке

При переключении вкладок из скрипта всё моргает, конечно, но куда деваться...

3

Re: Создание таблиц из скриптов на нужной вкладке

< reserved >

4

Re: Создание таблиц из скриптов на нужной вкладке

а если через пункт меню "переместить на вкладку"?

5

Re: Создание таблиц из скриптов на нужной вкладке

toxa пишет:

а если через пункт меню "переместить на вкладку"?

Да, вариант. Надо будет поискать подходы. Спасибо за идею!

6 (2021-02-14 12:49:42 отредактировано Kolossi)

Re: Создание таблиц из скриптов на нужной вкладке

Добрый день.
Все вроде отлично, но что-то не так в датском королевстве c позиционированием окна.
Сделал из вашего кода функцию в свою библиотечку:
--

function OpenTable(Name,kid) -- функция открытия таблицы (kid) в нужной вкладке (Name)
    local mmes=""
    local hQuikWnd = GetQuikMainWindowHandle() -- handle главного окна QUIK
    local hTabWnd = 0 --  handle окна вкладок
        if hQuikWnd > 0 then
            hTabWnd = w32.FindWindowEx(hQuikWnd, 0, "SysTabControl32", "")
            if hTabWnd ~= 0 and not w32.IsWindowVisible(hTabWnd) then -- отображение вкладок отключено
                hTabWnd = 0
            end
        end
    if hTabWnd > 0 then --  вкладки в терминале отображаются
        local prevIdx = w32.TabCtrl_GetCurFocus(hTabWnd)  --  индекс текущей активной вкладки
        local idxGr = w32.TabCtrl_GetItemIndexByText(hTabWnd, Name) -- индекс заданной вкладки
        if idxGr >= 0 then -- вкладка найдена
            w32.TabCtrl_SetCurFocus(hTabWnd, idxGr) -- переключение на найденную вкладку
            local txt = w32.TabCtrl_GetItemText(hTabWnd) --  название текущей активной вкладки
            mmes="   Вкладка " .. tostring(txt)
            CreateWindow(kid)
            w32.TabCtrl_SetCurFocus(hTabWnd, prevIdx) -- назад на исходную вкладку
        else
            CreateWindow(kid)
            local txt = w32.TabCtrl_GetItemText(hTabWnd)
            mmes="   Вкладка не найдена. Текущая" .. tostring(txt)
        end
    else -- вкладки не отображены, открываем в текущей
        CreateWindow(kid)
        mmes="   Вкладка текущая"
    end
    return mmes
end

Главный код:
        ...
    local addtxt=OpenTable("Дивиденды",table_id)
    SetWindowCaption(table_id,"  Закрытие дивидендных реестров. "..addtxt)
    SetWindowPos(table_id, 0,0, 600, 990)
        local a,b,c,d=GetWindowRect(table_id)
        message(tostring(a).."-"..tostring(b).."-"..tostring(c).."-"..tostring(d))

Вроде все отлично, таблица попадает прямиком во вкладку "Дивиденды" и message() возвращает 0-0-600-990

Однако левый верхний угол таблицы в окне "Дивиденды" где угодно, только не в 0,0
Что я не понимаю ?

7 (2021-02-14 13:46:48 отредактировано Kolossi)

Re: Создание таблиц из скриптов на нужной вкладке

А, понял!
Координаты таблицы надо передавать в текущее окно.
Получилось так:

function OpenTable(Name,kid,pos) -- функция открытия таблицы (kid) с координатами (pos) в нужной вкладке (Name)
    local mmes=""
    local hQuikWnd = GetQuikMainWindowHandle() -- handle главного окна QUIK
    local hTabWnd = 0 --  handle окна вкладок
        if hQuikWnd > 0 then
            hTabWnd = w32.FindWindowEx(hQuikWnd, 0, "SysTabControl32", "")
            if hTabWnd ~= 0 and not w32.IsWindowVisible(hTabWnd) then -- отображение вкладок отключено
                hTabWnd = 0
            end
        end
    if hTabWnd > 0 then --  вкладки в терминале отображаются
        local prevIdx = w32.TabCtrl_GetCurFocus(hTabWnd)  --  индекс текущей активной вкладки
        local idxGr = w32.TabCtrl_GetItemIndexByText(hTabWnd, Name) -- индекс заданной вкладки
        if idxGr >= 0 then -- вкладка найдена
            w32.TabCtrl_SetCurFocus(hTabWnd, idxGr) -- переключение на найденную вкладку
            local txt = w32.TabCtrl_GetItemText(hTabWnd) --  название текущей активной вкладки
            mmes="   Вкладка " .. tostring(txt)
            CreateWindow(kid)
            SetWindowPos(kid, pos.a, pos.b, pos.c, pos.d)
            w32.TabCtrl_SetCurFocus(hTabWnd, prevIdx) -- назад на исходную вкладку
        else
            CreateWindow(kid)
            SetWindowPos(kid, pos.a, pos.b, pos.c, pos.d)
            local txt = w32.TabCtrl_GetItemText(hTabWnd)
            mmes="   Вкладка не найдена. Текущая " .. tostring(txt)
        end
    else -- вкладки не отображены, открываем в текущей
        CreateWindow(kid)
        SetWindowPos(kid, pos.a, pos.b, pos.c, pos.d)
        mmes="   Вкладка текущая"
    end
    return mmes
end

...
    local pos={a=0,b=0,c=600,d=990}
    local addtxt=OpenTable("Дивиденды",table_id,pos)
    SetWindowCaption(table_id,"  Закрытие дивидендных реестров. "..addtxt)
...
Все супер, спасибо swerg!

8 (2021-02-14 14:33:52 отредактировано Kolossi)

Re: Создание таблиц из скриптов на нужной вкладке

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

9

Re: Создание таблиц из скриптов на нужной вкладке

У вас несколько скриптов одновременно создают окна? Именно одновременно?

10

Re: Создание таблиц из скриптов на нужной вкладке

Это я про запуск после загрузки квика.

Выделяешь все скрипты и запускаешь выделенные. В итоге часть окон не в тех вкладках.
Понятно почему и это не критично, можно запускать по одному.
Наверное если вдруг получится через меню "переместить во вкладку" то этого не будет.  Если что я первый в очереди )

11 (2024-06-05 16:15:30 отредактировано igor)

Re: Создание таблиц из скриптов на нужной вкладке

Обнаружил, что время выполнения оператора w32.TabCtrl_GetItemText(hTabWnd) очень большое. Точнее оно колеблется от 1мс до ~130мс (непонятно, от чего это зависит).
Никто не знает, чем это вызвано, и можно ли как-нибудь с этим бороться?
Задача - сделать так, чтобы скрипт постоянно знал, какая вкладка активна в данный момент времени.

12

Re: Создание таблиц из скриптов на нужной вкладке

igor пишет:

Задача - сделать так, чтобы скрипт постоянно знал, какая вкладка активна в данный момент времени.

У вас "данный момент" наступает так часто, что критичны миллисекунды?

Вообще "под капотом" там простой вызов непосредственно WinAPI функции, так что если и тормозит - то сама Windows в этом месте, видимо нет надобности для пользовательского интерфейса делать это супер быстро и стабильно.

Кстати, а вы не из main() случайно вызываете w32.TabCtrl_GetItemText(hTabWnd)?

13

Re: Создание таблиц из скриптов на нужной вкладке

Да, я из main() вызываю w32.TabCtrl_GetItemText(hTabWnd).
Миллисекунды действительно не критичны. Но здесь речь идёт о величине > 100мс (если не больше). А это уже может быть заметно. Ведь это подвешивает и весь остальной скрипт.
Мне это чем-то напоминает ситуацию с функцией Sleep(1), задержка от которой тоже колеблется от 1мс до ~16мс, а иногда и ещё больше (решается с помощью NtSetTimerResolution).
Вот я и подумал, что может быть аналогичная ситуация и с функцией w32.TabCtrl_GetItemText(hTabWnd). Т.е. возможно она, чтобы отработать, ожидает какого-то сигнала от Windows. И может быть здесь тоже есть какое-нибудь решение, аналогичное решению с функцией Sleep(1).

14

Re: Создание таблиц из скриптов на нужной вкладке

Я думаю, что не смотря на выполнение TabCtrl_GetItemText в другом потоке, она, однако, синхронизируется с основным потоком терминала в том смысле, что Windows синхронизирует обращения к оконной функции (а для получения результата Windows вызывает оконную функцию). Соответственно если основной поток занят (например, перерисовывает графики, обновляет таблицы в терминале при получении торговых данных), то и TabCtrl_GetItemText останавливается до замершения других обработчиков (не Lua, обработчиков терминала и Windows). Могу предположить, что в эти моменты и происходят "провалы" по скорости её ответа.

Так что думаю надо просто придумать другую идею вместо "затрахивания" вызовами TabCtrl_GetItemText.

Хотя я примерно могу предположить для какой задачи у вас сделана такая работа робота.

15

Re: Создание таблиц из скриптов на нужной вкладке

Здесь идея проста. Если каждую вкладку привязать к определённому инструменту, то чтобы скрипт знал, с каким инструментом ему работать, он должен знать, какая вкладка активна в данный момент.
Я не знаю, какая тут может быть идея, кроме периодического вызова TabCtrl_GetItemText. Можно было бы не циклически вызывать эту функцию, а например по клику левой кнопки мыши. Но тогда надо каким-то образом перехватить нажатие левой кнопки мыши...
Но пока у меня такая идея - создать вспомогательный скрипт, который и будет периодически вызывать TabCtrl_GetItemText и передавать имя активной вкладки в основной скрипт с помощью StaticVar. Я думаю, что в этом случае эта функция не будет подвешивать основной скрипт.
Время обновления названия активной вкладки, равное 100мс (и даже 200мс) вполне бы устроило. Главное чтобы это не подвешивало основной скрипт (там итак есть много чего, что могло бы его подвесить)).

16

Re: Создание таблиц из скриптов на нужной вкладке

Задача ваша понятна, но вот идей как это сделать лучше у меня так и не придумалось...