1

我正在编写一个脚本来制作可以在我的 TI Nspire CX CAS 2 计算器上打开和关闭的小窗口。添加新窗口效果很好,但尝试删除它们会导致我的软件在应该删除窗口的功能完成时崩溃。我也在我的计算器上试过它,它仍然卡住,但我能够关闭脚本然后重新打开它。当我重新打开它时,第 465 行出现“中断”错误,我的计算器的图片出现错误

screen = platform.window
screenx,screeny = screen.width(),screen.height()

-- system stuff

local password = nil
local passVerify = nil
local drawObjects = {}
local processes = {}
local rectangle = class()
local backgroundObj = class()
local taskbar = class()
local window = class()
local process = class()
local taskbarHeight = 20
local hasBeenSetup = false
local customSetupProcedures = {}
local isLogedIn = false
local draggingMode = {
move = 0,
left = 1,
top = 2,
right = 3,
bottom = 4
}
local readyToDraw = true
local currentDraggingMode = draggingMode.both
local selectedWindowForDragging = nil
local textures = {}
local processStatus = {
waiting = 0,
running = 1,
halted = 2,
dead = 3
}
local specialColors = {
taskbarColor = 0x00969E,
windowBackgroundColor = 0xF7F7F7,
windowTopBarColor = 0xA2A2A2,
windowCloseButtonColor = 0xFF5100,
windowMaximizeButtonColor = 0x00FF00,
windowMinimizeButtonColor = 0xFFFF00
}

function process:init(run,onKill)
    self.status = processStatus.waiting
    self.co = coroutine.create(run)
    self.onKill = onKill
    coroutine.resume(self.co,self)
end

function process:update()
    if self.status == processStatus.running then
        coroutine.resume(self.co)
    end
end

function process:halt()
    self.status = processStatus.halted
end

function process:resume()
    self.status = processStatus.waiting
end

function process:kill()
    readyToDraw = false
    self.status = processStatus.dead
    self.co = nil
    self.onKill()
    readyToDraw = true
end

function rectangle:init(x,y,width,height)
    self.x = x
    self.y = y
    self.width = width
    self.height = height
end

function rectangle:contains(x,y)
    return self.x<x and x<self.x+self.width and self.y<y and y<self.y+self.height
end

function taskbar:init()

end

function taskbar:draw(gc)
    gc:setColorRGB(specialColors.taskbarColor)
    gc:fillRect(0,screeny-taskbarHeight,screenx,screeny)
    --gc:drawImage(textures[1],0,screeny-20)
end

function taskbar:isWindow()
    return false
end

function window:init(x,y,width,height)
    self.x = x
    self.y = y
    self.draggedOnX = 0
    self.draggedOnY = 0
    self.width = width
    self.height = height
    self.icon = nil
    self.components = {}
    self.focusLevel = 0
    newWindowFocused(#drawObjects+1)
    self.resizable = true
    self:subclassInit(x,y,width,height)
end

function window:subclassInit(x,y,width,height)

end

function window:getFocusLevel()
    return self.focusLevel
end

function window:draw(gc)
    gc:setColorRGB(specialColors.windowBackgroundColor)
    gc:fillRect(self.x,self.y,self.width,self.height)
    gc:setColorRGB(specialColors.windowTopBarColor)
    gc:fillRect(self.x,self.y,self.width,10)
    gc:setColorRGB(specialColors.windowMinimizeButtonColor)
    gc:fillRect(self.x+self.width-29,self.y+1,8,8)
    gc:setColorRGB(specialColors.windowMaximizeButtonColor)
    gc:fillRect(self.x+self.width-19,self.y+1,8,8)
    gc:setColorRGB(specialColors.windowCloseButtonColor)
    gc:fillRect(self.x+self.width-9,self.y+1,8,8)
    self:drawComponents(gc)
end

function window:drawComponents(gc)
    for i in ipairs(self.components) do
        self.components[i]:draw(gc,self)
    end
end

function window:addComponent(component)
    i = #self.components+1
    self.components[i] = component
    return i
end

function window:decreaseFocus()
    self.focusLevel = self.focusLevel+1
end

function window:isWindow()
    return true
end

function window:contains(x,y)
    return self.x<x and self.y < y and self.width+self.x>x and self.height+self.y>y
end

function window:checkForMouse(x,y)
    if y-self.y <= 3 and self.resizable then
        cursor.set('resize row')
    elseif y-self.y>=self.height-3 and self.resizable then
        cursor.set('resize row')
    elseif x-self.x<=3 and self.resizable then
        cursor.set('resize column')
    elseif x-self.x>=self.width-3 and self.resizable then
        cursor.set('resize column')
    end
end

function window:click(x,y,n)
    self:focus(n)
    if y-self.y <= 3 and self.resizable then
       selectedWindowForDragging = self
       currentDraggingMode = draggingMode.top
    elseif y-self.y>=self.height-3 and self.resizable then
       selectedWindowForDragging = self
       currentDraggingMode = draggingMode.bottom
    elseif x-self.x<=3 and self.resizable then
       selectedWindowForDragging = self
       currentDraggingMode = draggingMode.left
    elseif x-self.x>=self.width-3 and self.resizable then
        selectedWindowForDragging = self
        currentDraggingMode = draggingMode.right
    elseif y-self.y <= 10 then
        if x>=self.x+self.width-10 then
            self:close()
        elseif x>=self.x+self.width-20 then
            self:maximize()
        elseif x>=self.x+self.width-30 then
            self:minimize()
        else
            selectedWindowForDragging = self
            currentDraggingMode = draggingMode.move
            self.draggedOnX = x - self.x
            self.draggedOnY = y - self.y
        end
    end
    self:clickComponents(x,y)
end

function window:clickComponents(x,y)
    
end

function newWindowFocused(n)
    for window in ipairs(drawObjects) do
        window = drawObjects[window]
        if window:isWindow() then
            if window:getFocusLevel() < n then
                window:decreaseFocus()
            end
        end
    end
end

function window:focus(n)
    self.focusLevel = -1
    newWindowFocused(n)
end

function window:minimize()
    
end

function window:maximize()

end

function window:close()
    processes[1]:kill()
end

function on.resize()
    screenx = screen:width()
    screeny = screen:height()
end

function on.mouseDown(x,y)
    minFocus = 0
    for i = 0,#drawObjects,1 do
        for windown in ipairs(drawObjects) do
            window=drawObjects[windown]
            if window:isWindow() then
                if window:getFocusLevel() == minFocus then
                    if window:contains(x,y) then
                        window:click(x,y,minFocus)
                        return
                    end
                    minFocus = minFocus+1
                end
            end
        end
    end
end

function on.mouseMove(x,y)
    cursor.set('default')
    if selectedWindowForDragging ~= nil then
        if currentDraggingMode == draggingMode.move then
            selectedWindowForDragging.x = x - selectedWindowForDragging.draggedOnX
            selectedWindowForDragging.y = y - selectedWindowForDragging.draggedOnY
            if selectedWindowForDragging.x+selectedWindowForDragging.draggedOnX<5 then selectedWindowForDragging.x = 5-selectedWindowForDragging.draggedOnX end
            if selectedWindowForDragging.x+selectedWindowForDragging.draggedOnX>screenx-5 then selectedWindowForDragging.x = screenx-selectedWindowForDragging.draggedOnX-5 end
            if selectedWindowForDragging.y<0 then selectedWindowForDragging.y=0 end
            if selectedWindowForDragging.y>screeny-taskbarHeight-5 then selectedWindowForDragging.y = screeny-taskbarHeight-5 end
            elseif currentDraggingMode == draggingMode.top then
                i = selectedWindowForDragging.draggedOnY + y
                selectedWindowForDragging.height = math.max(selectedWindowForDragging.height - selectedWindowForDragging.draggedOnY - y + selectedWindowForDragging.y,20)
                selectedWindowForDragging.y = i
            elseif currentDraggingMode == draggingMode.bottom then
                selectedWindowForDragging.height = math.max(y - selectedWindowForDragging.y,20)
            elseif currentDraggingMode == draggingMode.left then
                i = selectedWindowForDragging.draggedOnX + x
                selectedWindowForDragging.width = math.max(selectedWindowForDragging.width - selectedWindowForDragging.draggedOnX - x + selectedWindowForDragging.x,20)
                selectedWindowForDragging.x = i
            elseif currentDraggingMode == draggingMode.right then
                selectedWindowForDragging.width = math.max(x - selectedWindowForDragging.x,20)
        end
    end
    
        minFocus = 0
        for i = 0,#drawObjects,1 do
            for windown in ipairs(drawObjects) do
                window=drawObjects[windown]
                if window:isWindow() then
                    if window:getFocusLevel() == minFocus then
                        if window:contains(x,y) then
                            window:checkForMouse(x,y)
                            return
                        end
                        minFocus = minFocus+1
                    end
                end
            end
        end
end

function on.mouseUp(x,y)
    selectedWindowForDragging = nil
end

local calculator = class(window)

function calculator:subclassInit()
    self.width = 60
    self.height = 90
    self.resizable = false
    self.number = ''
    print(self.number)
    self.button1 = rectangle(5,22,13,10)
    self.button2 = rectangle(24,22,14,10)
    self.button3 = rectangle(44,22,13,10)
    self.button4 = rectangle(5,34,13,10)
    self.button5 = rectangle(24,34,14,10)
    self.button6 = rectangle(44,34,13,10)
    self.button7 = rectangle(5,45,13,10)
    self.button8 = rectangle(24,45,14,10)
    self.button9 = rectangle(44,45,13,10)
    self.button0 = rectangle(24,57,14,10)
    self.buttonC = rectangle(5,57,13,10)
    self.buttonDot = rectangle(44,57,13,10)
    self.buttonPlus = rectangle(6,70,7,7)
    self.buttonMinus = rectangle(15,70,7,7)
    self.buttonMultiply = rectangle(40,70,7,7)
    self.buttonDivide = rectangle(49,70,7,7)
    self.buttonEquals = rectangle(24,69,14,8)
end

function calculator:drawComponents(gc)
    --gc:drawImage(textures[2],self.x,self.y+10)
    gc:setColorRGB(0x000000)
    gc:setFont('sansserif','r',6)
    if #self.number < 10 then
        gc:drawString(string.sub(self.number,0,#self.number),self.x+5,self.y+13)
    else
        gc:drawString(string.sub(self.number,#self.number-9,#self.number),self.x+5,self.y+13)
        print(self.number)
    end
end

function calculator:clickComponents(x,y)
    x = x-self.x
    y = y-self.y-10
    if self.button1:contains(x,y) then self.number = self.number..'1' elseif
    self.button2:contains(x,y) then self.number = self.number..'2' elseif
    self.button3:contains(x,y) then self.number = self.number..'3' elseif
    self.button4:contains(x,y) then self.number = self.number..'4' elseif
    self.button5:contains(x,y) then self.number = self.number..'5' elseif
    self.button6:contains(x,y) then self.number = self.number..'6' elseif
    self.button7:contains(x,y) then self.number = self.number..'7' elseif
    self.button8:contains(x,y) then self.number = self.number..'8' elseif
    self.button9:contains(x,y) then self.number = self.number..'9' elseif
    self.button0:contains(x,y) then self.number = self.number..'0' elseif
    self.buttonPlus:contains(x,y) then self.number = self.number..'+' elseif
    self.buttonMinus:contains(x,y) then self.number = self.number..'-' elseif
    self.buttonMultiply:contains(x,y) then self.number = self.number..'*' elseif
    self.buttonDivide:contains(x,y) then self.number = self.number..'/' elseif
    self.buttonDot:contains(x,y) then self.number = self.number..'.' elseif
    self.buttonEquals:contains(x,y) then
        if not pcall(function()self.number = ''..math.eval(self.number)end) then self.number = 'error' end
    elseif
    self.buttonC:contains(x,y) then self.number = '' end
end


function backgroundObj:draw(gc)
    gc:setColorRGB(0xC4C4C4)
    gc:fillRect(0,0,screenx,screeny-taskbarHeight)
    --gc:drawImage(textures[0],screenx/2-50,(screeny-taskbarHeight)/2-50)
end

function backgroundObj:isWindow()
    return false
end

function loadTextures()
    --textures[0]=image.new(_R.IMG.logo)
    --textures[1]=image.new(_R.IMG.startMenuButton)
    --textures[2]=image.new(_R.IMG.calculator)
end

function on.construction()
    timer.start(1/30)
    checkForSetup()
    checkForLogin()
end

function on.timer()
    screen:invalidate()
end

function encrypt(str,key)
    result = ''
    for i = 1,#str,1 do
        result = result..string.char(math.abs(string.byte(str:sub(i,i))+key+i)%422)
    end
    return result
end
function decrypt(str,key)
    result = ''
    for i = 1,#str,1 do
       result = result..string.char(math.abs((string.byte(str:sub(i,i))-key-i)%422))
    end
    return result
end

function checkForLogin()
    
end

function checkForSetup()
    if not hasBeenSetup then
        print('loading textures...')
        loadTextures()
        print('setting up graphics...')
        setupGraphics()
        print('executing default setup procedure...')
        print('setting up password...')
        setupPassword()
        print('executing custom setup procedures...')
        for funct in ipairs(customSetupProcedures) do
            funct()
        end
    end
    hasBeenSetup = true
end

function setupGraphics()
    processes[1] = process(
    function(proc)
        drawObjects[1] = backgroundObj()
    end,
    function()
       drawObjects[1] = nil
    end)
    drawObjects[2] = taskbar()
end

function setupPassword()
    w1 = calculator(50,100,100,100)
    drawObjects[3] = w1
    w2 = window(0,50,100,100)
    drawObjects[4] = w2
end

--system stuff

--graphics stuff

function on.paint(gc)
    if readyToDraw then
    if drawObjects[1]~=nil then
    drawObjects[1]:draw(gc)
    end
    focus = 0
    for i in ipairs(drawObjects) do
        window = drawObjects[i]
        if window:isWindow() then
            focus = math.max(focus,window:getFocusLevel())
        end
    end
    while focus>=0 do
        for i in ipairs(drawObjects) do
            window = drawObjects[i]
            if window:isWindow() and window:getFocusLevel()==focus then
                window:draw(gc)
                focus = focus-1
                break
            end
        end
    end
    drawObjects[2]:draw(gc)
    end
end

--graphics stuff

--default programs

--default programs


编辑:我刚刚发现,如果您在学生软件中运行脚本并且它陷入循环,按 F12 会中断循环(就像实际计算器上的主页按钮一样)。

4

1 回答 1

1

on.paint您的问题是您有机会在函数中进入无限循环。

你在这里做检查:

    if drawObjects[1]~=nil then
        drawObjects[1]:draw(gc)
    end

如果此检查false意味着以下 for 循环将运行 0 次,则ipairs希望先查看索引1或退出:

    focus = 0
    for i in ipairs(drawObjects) do -- Will run 0 times.
        window = drawObjects[i]
        if window:isWindow() then
            focus = math.max(focus,window:getFocusLevel())
        end
    end

这意味着您的 while 循环条件将无限期运行,因为与循环体中将发生focus >= 0相同的问题,并且永远不会改变ipairs(drawObjects)focus0

    while focus>=0 do
        for i in ipairs(drawObjects) do -- Will run 0 times.
            window = drawObjects[i]
            if window:isWindow() and window:getFocusLevel()==focus then
                window:draw(gc)
                focus = focus-1
                break
            end
        end
    end

您可以通过默认focus来解决此问题,-1另外您需要drawObjects[2]在使用它之前检查是否为 nil。


或者,可能是更好的选择,将您的支票更改为

    if drawObjects[1] == nil then
       return -- bail out of function we dont have anything to draw
    end
    drawObjects[1]:draw(gc)
于 2020-08-12T15:17:24.950 回答