невидимый столбец создается автоматически и не имеет номера. Все что создается пользователем начинается с любого номера, главное что бы они были по возрастанию, даже 150,180,200, и тд
Евгений, Ничего подобного! Я невидимые столбцы создаю сам - они не для юзера, а для самого скрипта. Вот так: AddColumn(T,0,"",true,QTABLE_STRING_TYPE,0); AddColumn(T,1,"Тикер",true,QTABLE_STRING_TYPE,8); ...
Для того что бы была возможность вставлять новые колонки без переделки всей таблицы лучше нумерацию делать через 10, чтобы можно было добавлять 11,12, колонки например
Евгений, Вот уж извините! Это источник ТАКИХ глюков, с которыми Вы потом в жисть не разберётесь! Я даже при изменении строк в таблице перебиваю её заново ( Clear + InsertRow)! А при пропадании текста в таблице и вообще приходится делать DestroyTable + AllocTable!
Владимир написал: Евгений, Вот уж извините! Это источник ТАКИХ глюков, с которыми Вы потом в жисть не разберётесь! Я даже при изменении строк в таблице перебиваю её заново ( Clear + InsertRow)! А при пропадании текста в таблице и вообще приходится делать DestroyTable + AllocTable!
Евгений, Нет, всё намного хуже. У меня четверть, если не треть всего кода посвящена именно компенсации различных глюков. Из непобеждённых остался такой: при обрыве и восстановлении связи эта скотина присылает целую колоду прерываний OnTrade,некоторые из которых были исполнены ещё вчера!
Евгений, Ну я уж и не знаю, каким местом можно ТАКОЕ задумывать!
Для меня в своё время было шоком, что на одно событие приходят несколько прерываний, потом - что они приходят вразнобой, теперь вот это...
Да сделать-то многое можно - труднее всего выявить ошибку, исправить на порядок проще. Но мне просто противно обрабатывать подобные глюки - тем более, что они иногда резко усложняют код. Например, удаление несработавших заявок - это просто песня! Хотя я вообще никак не контролирую, сработает KILL_ORDER или нет. И прерывания OnOrder выбросил нафиг, как и подавляющее большинство остальных.
Выкладываю те самые файлы из документации так как потратил на их копирование из pdf кучу времени, может хоть кому то удастся его сэкономить
Скрытый текст
--table_object.lua dofile (getScriptPath() .. "\\quik_table_wrapper.lua") dofile (getScriptPath() .. "\\ntime.lua") stopped = false function format1(data) return string.format("0x%08X", data) end function format2(data) return string.format("%06d", data) end function OnStop(s) stopped = true end function main() -- поворачивающиеся «палочки» в заголовке таблицы local palochki = {"-","\\", "|", "/"} -- создать экземпляр QTable t = QTable.new() if not t then message("error!", 3) return else message("table with id = " ..t.t_id .. " created", 1) end -- добавить два столбца с функциями форматирования -- в первом столбце – hex-значения, во втором – целые числа t:AddColumn("test1", QTABLE_INT_TYPE, 10,format1) t:AddColumn("test2", QTABLE_INT_TYPE, 10, format2) -- добавить столбцы без форматирования t:AddColumn("test3", QTABLE_CACHED_STRING_TYPE, 50) t:AddColumn("test4", QTABLE_TIME_TYPE, 50) t:AddColumn("test5", QTABLE_CACHED_STRING_TYPE, 50) t:SetCaption("Test") t:Show() i=1 -- исполнять цикл, пока пользователь не остановит скрипт из диалога управления while not stopped do -- если таблица закрыта, то показать ее заново -- при этом все предыдущие данные очищаются if t:IsClosed() then t:Show() end -- на каждой итерации повернуть «палочку» на 45 градусов t:SetCaption("QLUA TABLE TEST " .. palochki[i%4 +1]) -- метод добавит в таблицу новую строчку и вернет ее номер local row = t:AddLine() t:SetValue(row, "test1", row, i) t:SetValue(row, "test2", row, i) -- заполнить ячейку текущим заголовком таблицы -- тип столбца – строковый, поэтому последний параметр пропускается SetCell(t.t_id, row, 3, GetWindowCaption(t.t_id)) _date = os.date("*t") -- 4-й столбец заполнить данными типа время (число в формате <ЧЧММСС>) -- Функция для строкового представления времени определена в файле --ntime.lua -- Функция NiceTime возвращает строку SetCell(t.t_id, row, 4,NiceTime(_date) .. string.format(" (%02d:%02d:%02d)", _date.hour,_date.min, _date.sec),_date.hour*10000+_date.min*100 +_date.sec) -- пятый столбец имеет строковый тип и заполняется результатом --выполнения функции NiceTime -- исходный код функции взят из виджета Conky Lua для Ubuntu SetCell(t.t_id, row, 5, NiceTime(_date)) sleep(1000) i=i+1 end message("finished") end
--quik_table_wrapper.lua
Скрытый текст
-- Перегрузка функции message с необязательным вторым параметром old_message = message function message(v, i) old_message(tostring(v), i or 1) end QTable ={} QTable.__index = QTable -- Создать и инициализировать экземпляр таблицы QTable function QTable.new() local t_id = AllocTable() if t_id ~= nil then q_table = {} setmetatable(q_table, QTable) q_table.t_id=t_id q_table.caption = "" q_table.created = false q_table.curr_col=0 -- таблица с описанием параметров столбцов q_table.columns={} return q_table else return nil end end function QTable:Show() -- отобразить в терминале окно с созданной таблицей CreateWindow(self.t_id) if self.caption ~="" then -- задать заголовок для окна SetWindowCaption(self.t_id, self.caption) end self.created = true end function QTable:IsClosed() -- если окно с таблицей закрыто, возвращает «true» return IsWindowClosed(self.t_id) end function QTable:delete() -- удалить таблицу DestroyTable(self.t_id) end function QTable:GetCaption() if IsWindowClosed(self.t_id) then return self.caption else -- возвращает строку, содержащую заголовок таблицы return GetWindowCaption(self.t_id) end end -- Задать заголовок таблицы function QTable:SetCaption(s) self.caption = s if not IsWindowClosed(self.t_id) then res = SetWindowCaption(self.t_id, tostring(s)) end end -- Добавить описание столбца <name> типа <c_type> в таблицу -- <ff> – функция форматирования данных для отображения function QTable:AddColumn(name, c_type, width, ff ) local col_desc={} self.curr_col=self.curr_col+1 col_desc.c_type = c_type col_desc.format_function = ff col_desc.id = self.curr_col self.columns[name] = col_desc -- <name> используется в качестве заголовка таблицы AddColumn(self.t_id, self.curr_col, name, true, c_type, width) end function QTable:Clear() -- очистить таблицу Clear(self.t_id) end -- Установить значение в ячейке function QTable:SetValue(row, col_name, data) local col_ind = self.columns[col_name].id or nil if col_ind == nil then return false end -- если для столбца задана функция форматирования, то она используется local ff = self.columns[col_name].format_function if type(ff) == "function" then -- в качестве строкового представления используется -- результат выполнения функции форматирования SetCell(self.t_id, row, col_ind, ff(data), data) return true else SetCell(self.t_id, row, col_ind, tostring(data), data) end end function QTable:AddLine() -- добавляет в конец таблицы пустую строчку и возвращает ее номер return InsertRow(self.t_id, -1) end function QTable:GetSize() -- возвращает размер таблицы return GetTableSize(self.t_id) end -- Получить данные из ячейки по номеру строки и имени столбца function QTable:GetValue(row, name) local t={} local col_ind = self.columns[name].id if col_ind == nil then return nil end t = GetCell(self.t_id, row, col_ind) return t end -- Задать координаты окна function QTable:SetPosition(x, y, dx, dy) return SetWindowPos(self.t_id, x, y, dx, dy) end -- Функция возвращает координаты окна function QTable:GetPosition() top, left, bottom, right = GetWindowRect(self.t_id) return top, left, right-left, bottom-top end
--ntime.lua
Скрытый текст
words = {"one ", "two ", "three ", "four ", "five ", "six ", "seven ", "eight ", "nine "} levels = {"thousand ", "million ", "billion ", "trillion ", "quadrillion ", "quintillion ", "sextillion ", "septillion ", "octillion ", [0] = ""} iwords = {"ten ", "twenty ", "thirty ", "forty ", "fifty ", "sixty ", "seventy ", "eighty ", "ninety "} twords = {"eleven ", "twelve ", "thirteen ", "fourteen ", "fifteen ", "sixteen ", "seventeen ", "eighteen ", "nineteen "} function digits(n) local i, ret = -1 return function() i, ret = i + 1, n % 10 if n > 0 then n = math.floor(n / 10) return i, ret end end end level = false function getname(pos, dig) level = level or pos % 3 == 0 if(dig == 0) then return "" end local name = (pos % 3 == 1 and iwords[dig] or words[dig]) .. (pos % 3 == 2 and "hundred " or "") if(level) then name, level = name .. levels[math.floor(pos / 3)], false end return name end function numberToWord(number) if(number == 0) then return "zero" end vword = "" for i, v in digits(number) do vword = getname(i, v) .. vword end for i, v in ipairs(words) do vword = vword:gsub("ty " .. v, "ty-" .. v) vword = vword:gsub("ten " .. v, twords[i]) end return vword end function _Time(t) hour = t.hour minute = t.min hour = hour % 12 if(hour == 0) then hour, nextHourWord = 12, "one " else nextHourWord = numberToWord(hour+1) end hourWord = numberToWord(hour) if(minute == 0 ) then return hourWord .. "o'clock" elseif(minute == 30) then return "half past " .. hourWord elseif(minute == 15) then return "a quarter past " .. hourWord elseif(minute == 45) then return "a quarter to " .. nextHourWord else if(minute < 30) then return numberToWord(minute) .. "past " .. hourWord else return numberToWord(60-minute) .. "to " .. nextHourWord end end end function _Seconds(s) return numberToWord(s) end function NiceTime(t) return _Time(t) .."and ".. _Seconds(t.sec) .. "second" end
--x0x.lua
Скрытый текст
--Пример реализации игры «Крестики-нолики» --[[ TIC-TAC-TOE by Evan Hahn (http://evanhahn.com/how-to-code-tic-tac-toe-and-a-lua-implementation/ --]] ---------------------------------------------- -- Configuration (change this if you wish!) -- ---------------------------------------------- t_id=nil --grid -- Are they playable by human or computer-controlled? PLAYER_1_HUMAN = true PLAYER_2_HUMAN = false -- Board size BOARD_RANK = 3 -- The board will be this in both dimensions. -- Display stuff PLAYER_1 = "[x]" -- Player 1 is represented by this. Player 1 goes first. PLAYER_2 = "[o]" -- Player 2 is represented by this. EMPTY_SPACE = "[ ]" -- An empty space is displayed like this. DISPLAY_HORIZONTAL_SEPARATOR = "-" -- Horizontal lines look like this. DISPLAY_VERTICAL_SEPARATOR = " | " -- Vertical lines look like this --[[ ################################################################### #### Don't mess with things below here unless you are brave #### ################################################################### --]] ------------------------ -- More configuration -- ------------------------ MAX_BOARD_RANK = 100 -- Won't run above this number. Prevents crashes. ------------------------------------------------------- -- Don't run if the board is larger than the maximum -- ------------------------------------------------------- if BOARD_RANK > MAX_BOARD_RANK then os.exit(0) end ----------------------------- -- Create board (2D table) -- ----------------------------- space = {} for i = 0, (BOARD_RANK - 1) do space[i] = {} for j = 0, (BOARD_RANK - 1) do space[i][j] = nil -- start each space with nil end end --------------------- -- Board functions -- --------------------- -- get the piece at a given spot function getPiece(x, y) return space[x][y] end -- get the piece at a given spot; if nil, return " " -- this is useful for output. function getPieceNoNil(x, y) if getPiece(x, y) ~= nil then return getPiece(x, y) else return EMPTY_SPACE end end -- is that space empty? function isEmpty(x, y) if getPiece(x, y) == nil then return true else return false end end -- place a piece there, but make sure nothing is there already. -- if you can't play there, return false. function placePiece(x, y, piece) if isEmpty(x, y) == true then space[x][y] = piece return true else return false end end -- is the game over? function isGameOver() if checkWin() == false then -- if there is no win... for i = 0, (BOARD_RANK - 1) do -- is the board empty? for j = 0, (BOARD_RANK - 1) do if isEmpty(i, j) == true then return false end end end return true else -- there is a win; the game is over return true end end -- create a string made up of a certain number of smaller strings -- this is useful for the display. function repeatString(to_repeat, amount) if amount <= 0 then return "" end local to_return = "" for i = 1, amount do to_return = to_return .. to_repeat end return to_return end -- display the board. -- this uses the configuration file pretty much entirely. function displayBoard() for i = (BOARD_RANK - 1), 0, -1 do for j = 0, (BOARD_RANK - 1) do -- generate that row local piece = getPieceNoNil(j, i) SetCell(t_id, i+1, j+1, piece) end end end ------------------------------------------------- -- Create regions (I admit this is a bit ugly) -- ------------------------------------------------- -- declare region and a number to increment region = {} region_number = 0 -- vertical for i = 0, (BOARD_RANK - 1) do region[region_number] = {} for j = 0, (BOARD_RANK - 1) do region[region_number][j] = {} region[region_number][j]["x"] = i region[region_number][j]["y"] = j end region_number = region_number + 1 end -- horizontal for i = 0, (BOARD_RANK - 1) do region[region_number] = {} for j = 0, (BOARD_RANK - 1) do region[region_number][j] = {} region[region_number][j]["x"] = j region[region_number][j]["y"] = i end region_number = region_number + 1 end -- diagonal, bottom-left to top-right region[region_number] = {} for i = 0, (BOARD_RANK - 1) do region[region_number][i] = {} region[region_number][i]["x"] = i region[region_number][i]["y"] = i end region_number = region_number + 1 -- diagonal, top-left to bottom-right region[region_number] = {} for i = (BOARD_RANK - 1), 0, -1 do region[region_number][i] = {} region[region_number][i]["x"] = BOARD_RANK - i - 1 region[region_number][i]["y"] = i end region_number = region_number + 1 ---------------------- -- Region functions -- ---------------------- -- get a region function getRegion(number) return region[number] end -- check for a win in a particular region. -- returns a number representation of the region. occurrences of player 1 -- add 1, occurrences of player 2 subtract 1. so if there are two X pieces, -- it will return 2. one O will return -1. function checkWinInRegion(number) local to_return = 0 for i, v in pairs(getRegion(number)) do local piece = getPiece(v["x"], v["y"]) if piece == PLAYER_1 then to_return = to_return + 1 end if piece == PLAYER_2 then to_return = to_return - 1 end end return to_return end -- check for a win in every region. -- returns false if no winner. -- returns the winner if there is one. function checkWin() for i in pairs(region) do local win = checkWinInRegion(i) if math.abs(win) == BOARD_RANK then if win == math.abs(win) then return PLAYER_1 else return PLAYER_2 end end end return false end ------------------ -- UI Functions -- ------------------ -- human play function humanPlay(piece) message("Human turn") displayBoard() local placed = false while placed == false do -- loop until they play correctly sleep(100) if g_X ~= -1 and g_Y ~=-1 then local x = tonumber(g_Y)-1 local y = tonumber(g_X)-1 g_X = -1 g_Y= -1 message("clicked in " .. x .. " and " .. y) placed = placePiece(x, y, piece) if placed == false then message("I'm afraid you can't play there!") end end end displayBoard() end -- AI play function AIPlay(piece) -- am I negative or positive? local me = 0 if piece == PLAYER_1 then me = 1 end if piece == PLAYER_2 then me = -1 end -- look for a region in which I can win for i in pairs(region) do local win = checkWinInRegion(i) if win == ((BOARD_RANK - 1) * me) then for j, v in pairs(getRegion(i)) do if isEmpty(v["x"], v["y"]) == true then placePiece(v["x"], v["y"], piece) return end end end end -- look for a region in which I can block for i in pairs(region) do local win = checkWinInRegion(i) if win == ((BOARD_RANK - 1) * (me * -1)) then for j, v in pairs(getRegion(i)) do if isEmpty(v["x"], v["y"]) == true then placePiece(v["x"], v["y"], piece) return end end end end -- play first empty space, if no better option for i = 0, (BOARD_RANK - 1) do for j = 0, (BOARD_RANK - 1) do if placePiece(i, j, piece) ~= false then return end end end end g_X=-1 g_Y=-1 function event_callback(t_id, msg, par1, par2) if msg == QTABLE_LBUTTONDOWN then g_X = par1 g_Y = par2 end end old_message = message local fmt = string.format function message(v, t) t= t or 1 old_message(tostring(v), t) end function main() t_id = AllocTable() AddColumn(t_id, 1, "", true, QTABLE_CACHED_STRING_TYPE, 5) AddColumn(t_id, 2, "", true, QTABLE_CACHED_STRING_TYPE, 5) AddColumn(t_id, 3, "", true, QTABLE_CACHED_STRING_TYPE, 5) CreateWindow(t_id) for i=1, 3 do row = InsertRow(t_id, -1) SetCell(t_id, row, 1, "[ ]") SetCell(t_id, row, 2, "[ ]") SetCell(t_id, row, 3, "[ ]") end SetTableNotificationCallback(t_id, event_callback) message("Welcome to Tic-Tac-Toe!") -- play the game until someone wins while true do sleep(100) -- break if the game is won if isGameOver() == true then break end -- player 1 if PLAYER_1_HUMAN == true then humanPlay(PLAYER_1) else AIPlay(PLAYER_1) end if isGameOver() == true then break end if PLAYER_2_HUMAN == true then humanPlay(PLAYER_2) else AIPlay(PLAYER_2) end end -- show the final board displayBoard() -- write who won, or if there is a tie win = checkWin() if win == false then message("Tie game!\n") else message(win) message(" wins!\n") end end
Евгений, что вы имеете ввиду под "вынесена за пределы квика"?
Сбросить и загрузить табличные данные нетрудно. Надо только добавлять строки и столбцы с идентификаторами идущими по порядку начиная с 1.
Код
local function savetable ( tbl, fname, separator )
local file, errmsg = io.open ( fname, "w" )
if not file then error ( errmsg ) end
local nr, nc = GetTableSize ( tbl )
if not nr or not nc then error ( "Invalid table handler: " .. tostring ( tbl ) ) end
if not separator then separator = "," end
local replace = "\\" .. separator
local data = { }
for r = 1, nr do
for c = 1, nc do
local v = GetCell ( tbl, r, c )
data[ #data + 1 ] = tostring ( v.value == 0 and v.image or tostring ( v.value ) ):gsub ( separator, replace )
data[ #data + 1 ] = separator
end
data[ #data ] = "\n"
end
file:write ( table.concat ( data ) )
file:close ( )
end
local function loadtable ( tbl, fname, separator )
local file, errmsg = io.open ( fname, "r" )
if not file then error ( errmsg ) end
local nr, nc = GetTableSize ( tbl )
if not nr or not nc then error ( "Invalid table handler: " .. tostring ( tbl ) ) end
if not separator then separator = "," end
local replace = "\\" .. separator
local pattern = "[^" .. separator .. "]*"
local r, c= 0, 0
for line in file:lines ( ) do
c = 0
r = r + 1
for tok in line:gmatch ( pattern ) do
col = col + 1
tok = tok:gsub ( replace, separator )
local num = tonumber ( tok )
if num then
SetCell ( tbl, r, c, tok, num )
else
SetCell ( tbl, r, c, tok )
end
end
end
end
Вы приводите пример сохранения таблицы Lua в файл и загрузку, это не то.
Я имел в виду видимую таблицу Quik, созданную из скрипта , которую можно вынести за пределы окна программы на другой монитор например.Сейчас это доступно для таблиц при помощи ctrl +alt и захвата таблицы мышкой с переносом за область квика, но таблица созданная из Lua не сохраняется в таком положении
Евгений, ЗАЧЕМ?! Это же ВАШ скрипт создавал эту таблицу! Следовательно, он всё и знает. Это всего лишь таблица визуализации, она только для юзера, а "настоящие" данные должны храниться в таблицах Lua. У меня (как и у Вас, насколько я вижу) каждая строка таблицы соответствует отдельному тикеру. Вы думаете, зачем у меня невидимый нулевой столбец? Там как раз и хранится "настоящий" идентификатор этого тикера в моей Lua-таблице (точнее, дереве), и все необходимые действия с инструментом я провожу там, и ТОЛЬКО там! И там можно делать с ними, что хошь: "выносить за пределы Quik", сохранить в файл и т.д. Я сейчас делаю это каждые 5 минут (на случай падения Квика, которые происходят всё чаще).
Клава и мышь обрабатываются в прерываниях (коллбеках), установленных по SetTableNotificationCallback. Я, правда, не знаю, есть ли там комбинации с ctrl и alt, но мне пока что хватает мыши и пробела с Enter.
Артем, ЩАЗ! Что толку от Ваших "идентификаторов, идущих по порядку начиная с 1"? А ну, кликните мышой по заголовку какого-нить столбца! Что случится с Вашими "идентификаторами"? Правильно, Большая Жопа. Обсуждалось тут уже (в т.ч. с моим участием).
Евгений написал: Я имел в виду видимую таблицу Quik, созданную из скрипта , которую можно вынести за пределы окна программы на другой монитор например.
Может быть вам подойдет следующий вариант. Вы оформляете функцию создания таблицы QUIK в виде отдельного файла. Далее загружаете этот файл с помощью loadfile в нужный свой скрипт и в нужном месте запускаете байт-код, полученный в loadfile, для создания таблицы QUIK. Это можно делать на любом рабочем месте.
Нет это все не то, Вы не поняли то что мне надо)), мой вопрос лежит в области визуализации и размещения таблицы (окна) Quik созданной из Lua. Думаю тут надо использовать w32.dll для автоматизации переноса окна таблицы за пределы квика, методом отсылки сообщений типа этому окну C++ BOOL PostMessageA( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam );
Евгений, Вот уж что меня ВААПЩЕ не интересует! Но если очень хочется - способ один: переместить туда необходимые ДАННЫЕ и там снова делать с ними, что хошь. Причём ЛЮБЫЕ данные, а не только сраную таблицу. Тем более, что сервис для визуализации в Квике достаточно убогий.
Владимир, действительно. Опять я наивно полагал что сделано по-человечески а не через задницу - разбалован совсем западными программистами видимо. 😐
Вопрос стоит в том, чтобы программно вывесить таблицу за пределы окна квика, и таковой функционал на стороне Lua начисто отсутствует. Если вручную его вытащить, то потом можно координаты ставить как угодно, но если этого не сделать, то таблица будет просто двигаться внутри окна квика и просто делать километровые скролбары. Тут вообще имел бы смысл чтобы квик работал в многооконном режиме, а не заталкивал все окошки в главное окно.
Артем, Во-первых, западные программисты ничем не лучше наших - был знаком лично с немалым их количеством, в т.ч. с виртуозами, в т.ч. с лучшим программистом мира 1993 года. Во-вторых, вопрос должен быть переформулирован как "вывесить ДАННЫЕ таблицы за пределы окна квика", и он достаточно легко может быть реализован. В-третьих, основная задача Квика - организация надёжной торговли ценными бумагами, и чем меньше он будет уметь ВНЕ этой задачи - тем лучше!
Владимир, было бы уместно в таком случае делать "безголовый" клиент, который по локалхосту может отправлять данные в браузер - а как пользователи будут их отображать это будет их личное дело. Как раз можно было бы делать скины, дополнительные данные отображать, с помощью WebGL рисовать, и прочие свистелки и перделки задействовать.
Артем, Да, "уместно в таком случае делать "безголовый" клиент", который будет принимать от юзеров заявки и давать им квитанции об их исполнении или отклонении. Это БАЗОВЫЙ уровень Квика. Ну, а дать ему дополнительно программный сервис или всякие там таблицы с графиками - это уже конкуренция между разработчиками софта для привлечения клиентов. В любом случае, базовый сервис должен работать БЕЗУКОРИЗНЕННО (по крайней мере, начиная с версии 1.1.1.3). А прочие свистелки и перделки" - это уже имеет значение только при обеспечении этого условия. А на деле что?
Артем написал: Владимир , было бы уместно в таком случае делать "безголовый" клиент, который по локалхосту может отправлять данные в браузер - а как пользователи будут их отображать это будет их личное дело.
Цитата
Артем написал: Артем , Да, "уместно в таком случае делать "безголовый" клиент", который будет принимать от юзеров заявки и давать им квитанции об их исполнении или отклонении. Это БАЗОВЫЙ уровень Квика.
Коротко, четко, практически манифест для разработчиков QUIK. ------ Глядя, на такие комментарии, мне хочет завершить мой конфликт с swerg. На самом деле, он старается помочь многим пользователям форума, Кроме того, он выкладывает свои профессиональные разработки, полезные многим пользователям.