Sign in to follow this  
Lord Henry

Sorting da Gridlist não funciona corretamente

Recommended Posts

Eae galera.

Encontrei um bug na lista do meu painel de ranking. Onde os valores numéricos que são decimais não ficam na ordem correta do maior pro menor nem vice-versa. Eles ficam aleatórios. Os valores inteiros ficam organizados corretamente.

Já configurei para a lista considerá-los como números usando guiGridSetItemText e setando o parâmetro number como true. Ele organiza os valores inteiros corretamente, mas os valores float não. Alguém sabe como resolver?

Segue a print mostrando o problema:

Spoiler

7bcrsFc1S6WEYa_VENlEsg.png

Os valores estão sendo cortados para somente 3 casas decimais usando a função math.round, que está funcionando perfeitamente.

Parte do script que preenche a lista:

Spoiler

function scoreInfo (names, kills, deaths, ratio, given, taken, copRatio)
	guiSetVisible (scoreWindow, true)
	guiSetVisible (closeGrid, true)
	showCursor (true)
	if names then
		for i, v in ipairs (names) do
			if type (ratio[i]) == "number" then
				ratio[i] = math.round (ratio[i], 3, "floor") -- Aplica o redutor decimal no ratio.
			end
			if type (copRatio[i]) == "number" then
				copRatio[i] = math.round (copRatio[i], 3, "floor") -- Aplica o redutor decimal no copRatio.
			end
			local row = guiGridListAddRow (scoreGrid)
			guiGridListSetItemText (scoreGrid, row, nameColumn, names[i], false, false)
			guiGridListSetItemText (scoreGrid, row, nilColumn, "|", false, false)
			guiGridListSetItemText (scoreGrid, row, killsColumn, kills[i], false, true)
			guiGridListSetItemText (scoreGrid, row, deathsColumn, deaths[i], false, true)
			guiGridListSetItemText (scoreGrid, row, ratioColumn, ratio[i], false, true)
			guiGridListSetItemText (scoreGrid, row, nullColumn, "|", false, false)
			guiGridListSetItemText (scoreGrid, row, givenColumn, given[i], false, true)
			guiGridListSetItemText (scoreGrid, row, takenColumn, taken[i], false, true)
			guiGridListSetItemText (scoreGrid, row, copColumn, copRatio[i], false, true)
			guiGridListSetItemColor (scoreGrid, row, nilColumn, 255, 0, 0)
			guiGridListSetItemColor (scoreGrid, row, nullColumn, 255, 0, 0)
		end
	end
end
addEvent ("showRank", true)
addEventHandler ("showRank", getRootElement(), scoreInfo)

 

 

Edited by Lord Henry

Share this post


Link to post

Provavelmente deve ser algum bug ele não funcionar com decimais...

Fiz um teste rápido aqui e se você deixar o conteúdo como string no guiGridListSetItemText (não definir o último argumento como true) a ordenação funciona!

Lua assim como outras linguagens convertem strings numéricas em números para fazer a comparação:

-- https://www.lua.org/cgi-bin/demo
if ("2.333" < "2.5555") then
	print("ok")
else
	print("fail")
end

 

  • Like 1

Share this post


Link to post

Sim. Mas antes eu não defini como number e mesmo assim bugava a organização. Dai converti pra number pra ver se resolvia e não mudou em nada.

function scoreInfo (names, kills, deaths, ratio, given, taken, copRatio)
	guiSetVisible (scoreWindow, true)
	guiSetVisible (closeGrid, true)
	showCursor (true)
	if names then
		for i, v in ipairs (names) do
			if type (ratio[i]) == "number" then
				ratio[i] = math.round (ratio[i], 3, "floor") -- Aplica o redutor decimal no ratio.
			end
			if type (copRatio[i]) == "number" then
				copRatio[i] = math.round (copRatio[i], 3, "floor") -- Aplica o redutor decimal no copRatio.
			end
			local row = guiGridListAddRow (scoreGrid, names[i], "|", kills[i], deaths[i], ratio[i], "|", given[i], taken[i], copRatio[i])
			guiGridListSetItemColor (scoreGrid, row, nilColumn, 255, 0, 0)
			guiGridListSetItemColor (scoreGrid, row, nullColumn, 255, 0, 0)
		end
	end
end
addEvent ("showRank", true)
addEventHandler ("showRank", getRootElement(), scoreInfo)

 

Share this post


Link to post

Sem usar guiGridListSetItemText

local numeros = {1,2,2.5,2.75,2.333,3,4,5,6,7,8,9}

local grid = guiCreateGridList ( 0.5, 0.5, 0.2, 0.3, true )
local column = guiGridListAddColumn( grid, "Números", 1 )
for _,n in ipairs(numeros) do
	local row = guiGridListAddRow ( grid, n )
end

GYyQAEL.jpg

===========================================

Usando guiGridListSetItemText

local numeros = {1,2,2.5,2.75,2.333,3,4,5,6,7,8,9}

local grid = guiCreateGridList ( 0.5, 0.5, 0.2, 0.3, true )
local column = guiGridListAddColumn( grid, "Números", 1 )
for _,n in ipairs(numeros) do
	local row = guiGridListAddRow ( grid )
	guiGridListSetItemText ( grid, row, column, n, false, false )
end

1BS0bGK.jpg

 

Ou seja, quando tenta-se adicionar os itens direto pelo guiGridListAddRow a ordenação com números decimais não funciona (aparentemente no caso dos decimais ele mantém a ordem em que foram acionados), porém usando guiGridListSetItemText funciona...

Se quiser manter como estava fazendo pode tentar usar table.sort antes de adicionar no gridList

Share this post


Link to post

No caso, devo usar guiGridSetItemText, mas deixando como false no parâmetro de number?

Edited by Lord Henry

Share this post


Link to post

Teste usando números inteiros de 2 dígitos também, tipo 10, 12, 23.

Share this post


Link to post

Continua não dando certo.

kmS3oqECRO_BrVzgY4wZbA.png

Os números decimais estão funcionando, mas os inteiros que são com mais de um dígito não aparecem na ordem correta. Ele considera 14 menor que 2.

Se eu deixar o parâmetro de number como true, os números inteiros funcionam bem, mas os decimais ficam aleatórios. (1.1 = 1.01 = 1.11)
Se eu deixar o parâmetro de number como false, os números decimais funcionam bem, mas os inteiros de 2 ou mais dígitos ficam errados. (14 < 2)

Edited by Lord Henry

Share this post


Link to post

É, realmente!

Única solução que pensei aqui é essa:

local numeros = {10,3,1,70,2,2.5,2.75,2.333,25,3,4,5,6,7,8,9}

table.sort(numeros)
local grid = guiCreateGridList ( 0.5, 0.5, 0.2, 0.3, true )
local column = guiGridListAddColumn( grid, "Números", 1 )
for _,n in ipairs(numeros) do
	local row = guiGridListAddRow ( grid )
	guiGridListSetItemText ( grid, row, column, n, false, true )
end

4O7AxUd.png

Share this post


Link to post

Teste nesta tabela:

scoreGrid = guiCreateGridList (10, 20, 580, 330, false)
nameColumn = guiGridListAddColumn (scoreGrid, "Player", 0.33)
numberColumn = guiGridListAddColumn (scoreGrid, "K/D", 0.1)
nomeTable = {"Nome5", "Nome3", "Nome7", "Nome9", "Nome1", "Nome2", "Nome4", "Nome8", "Nome10", "Nome6")
numberTable = {8,4.1,4.2,4.01,4.11,10,2,4.001,5,1}

 

Edited by Lord Henry

Share this post


Link to post

Se tentar usar o table.sort direto na tabela dos números irá perder a correspondência com a tabela dos nomes... algo do tipo deve resolver:

nomeTable = {"Nome5", "Nome3", "Nome7", "Nome9", "Nome1", "Nome2", "Nome4", "Nome8", "Nome10", "Nome6"}
numberTable = {8,4.1,4.2,4.01,4.11,10,2,4.001,5,1}

sort = {}
for i=1,#nomeTable do sort[i] = {nomeTable[i],numberTable[i]} end
table.sort(sort, function(a, b) return a[2] < b[2] end)

 

Share this post


Link to post

Cara, fui testar aqui e vi que realmente nem funciona certo!

Ele ordena como esperado, só que se você tentar ordenar a coluna do gridList de forma decrescente ele ainda buga nos decimais...

Share this post


Link to post

O problema está no fato dele não reconhecer numero decimal. Pois se reconhecesse, ele organizaria direito quando colocamos true no parâmetro number.

Share this post


Link to post

Tentei aqui reproduzir o bug que você tiveram, mas não consegui, usando o table.sort do código do MaligNos. Qual número decimal vocês testaram?

Share this post


Link to post
2 hours ago, DNL291 said:

Tentei aqui reproduzir o bug que você tiveram, mas não consegui, usando o table.sort do código do MaligNos. Qual número decimal vocês testaram?

Essa tabela de testes:

4 hours ago, Lord Henry said:

Teste nesta tabela:


scoreGrid = guiCreateGridList (10, 20, 580, 330, false)
nameColumn = guiGridListAddColumn (scoreGrid, "Player", 0.33)
numberColumn = guiGridListAddColumn (scoreGrid, "K/D", 0.1)
nomeTable = {"Nome5", "Nome3", "Nome7", "Nome9", "Nome1", "Nome2", "Nome4", "Nome8", "Nome10", "Nome6")
numberTable = {8,4.1,4.2,4.01,4.11,10,2,4.001,5,1}

 

 

Share this post


Link to post
10 hours ago, DNL291 said:

Aqui funcionou com essa tabela:

https://imgur.com/a/MWYrJAB

Você apenas realocou os elementos pelo script. Vc não clicou na coluna para reorganizar.

Preciso que os números fiquem na ordem correta quando eu clicar na coluna dos números. Tanto do maior pro menor, quanto do menor pro maior.

Pois a tabela que estou usando possui várias colunas de números, o usuário pode escolher qual delas quer usar o filtro.

Share this post


Link to post

Bom, fiz um código aqui pra resolver isso, foi algo meio radical mas consegui resolver. Na verdade eu fiz um sistema de ordenação personalizado, que usa as propriedades "SortDirection" e "SortColumnID" para fazer tudo separadamente da coluna ratio. Quanto à coluna ratio, eu usei o table.sort que já foi mostrado aqui no tópico.

Fiz tudo com detecção de clique nas áreas de cada coluna, sendo que a ordenação é feita pelo próprio script como já disse. Deixei o código comentado, testei ele e funcionou muito bem. Aqui está:


local sortTable = {
	-- nick, kills, deaths, ratio
	{ "Nome5", 10, 8, 8 },
	{ "Nome3", 2, 5, 4.1 },
	{ "Nome7", 3, 8, 4.2 },
	{ "Nome9", 4, 10, 4.01 },
	{ "Nome1", 5, 14, 4.11 },
	{ "Nome2", 12, 3, 10 },
	{ "Nome4", 2, 7, 5 },
	{ "Nome8", 20, 1, 2 },
	{ "Nome10", 5, 0, 1 },
	{ "Nome6", 7, 22, 4.001 }
}

local ratio_column = 4

--[[-------------------------------------------------------------
-	Você deve estruturar uma tabela para a lista
-	como acima.
-	
-	A coluna do ratio pode ser definida na variável 'ratio_column'
------------------------------------------------------------------]]

local columns = {}
local lastClickedColumn
local selectedRowText

addEventHandler( "onClientResourceStart", resourceRoot,
	function()
		createGridListInterface()
		showCursor (true)
		scoreInfo()
		
		-- mapeando as dimensões das colunas
		local gridX, gridY = guiGetPosition( scoreGrid, false )
		local columnStartX = gridX + 8
		local columnTop = gridY + 1
		local columnBottom = columnTop + 22

		columns[1] = {
					columnStartX,
					columnTop,
					columnStartX + guiGridListGetColumnWidth( scoreGrid, 1, false ),
					columnBottom
		}
		
		-- adicionando as posições das colunas na tabela
		for i=2, guiGridListGetColumnCount( scoreGrid ) do
	
			local left = columns[i-1][3]
			local columnW = guiGridListGetColumnWidth( scoreGrid, i, false )
			columns[i] = { left, columnTop, (left + columnW), columnBottom }
		end
		-- teste
		-- Descomente esta linha se quiser testar as áreas do clique das colunas
		--addEventHandler("onClientRender", root, drawLines)
	end
)

function createGridListInterface()
	scoreGrid = guiCreateGridList (10, 20, 580, 330, false)
	guiGridListSetSortingEnabled( scoreGrid, false )
	
	nameColumn = guiGridListAddColumn (scoreGrid, "Player", 0.33)
	kills = guiGridListAddColumn (scoreGrid, "kills", 0.2)
	deaths = guiGridListAddColumn (scoreGrid, "daths", 0.2)
	numberColumn = guiGridListAddColumn (scoreGrid, "ratio", 0.1)
	
	-- criando uma label por cima das colunas para evitar o redimensionamento manual
	local gridX, gridY = guiGetPosition( scoreGrid, false )
	guiSetProperty(guiCreateLabel(gridX, gridY, 580, 22, "", false), "AlwaysOnTop", "True")
end

function scoreInfo( direction )
	if direction then
		--[[-------------------------------------------------------------
		-	workaround para fazer a ordenação manual.
		-	por algum motivo que eu não consegui descobrir,
		-	as rows simplesmente não são atualizadas quando
		-	clica na coluna do ratio (talvez pelo uso do guiSetProperty).
		-	Nem mesmo removendo as colunas e recriando-as
		-	eu pude resolver, pois me surgiu outro bug com
		-	a posição das colunas
		-----------------------------------------------------------------]]
		
		destroyElement(scoreGrid)
		createGridListInterface()
		
		table.sort( sortTable, 
			function(a, b)
				if direction == "Ascending" then return a[ratio_column] > b[ratio_column]
				else return a[ratio_column] < b[ratio_column]
				end
			end
		)
	end
	for i,v in ipairs(sortTable) do
		local row = guiGridListAddRow (scoreGrid)
		guiGridListSetItemText ( scoreGrid, row, nameColumn, v[1], false, false )
		guiGridListSetItemText ( scoreGrid, row, kills, v[2], false, true )
		guiGridListSetItemText ( scoreGrid, row, deaths, v[3], false, true )
		guiGridListSetItemText ( scoreGrid, row, numberColumn, v[ratio_column], false, true )
		
		local itemText = guiGridListGetItemText( scoreGrid, row, 1 ) 
		if selectedRowText and (itemText == selectedRowText) then
			guiGridListSetSelectedItem( scoreGrid, row, 1 )
		end
	end
end

-- (teste) destacando as áreas de cada coluna
function drawLines()
	if not scoreGrid then return end
	for i=1, guiGridListGetColumnCount( scoreGrid ) do
		local left = columns[i][1]
		local top = columns[i][2]
		local right = columns[i][3]
		local bottom = columns[i][4]
	
		dxDrawLine ( left, top, right, top, tocolor(255, 20, 20), 1, true ) -- Top
		dxDrawLine ( left, top, left, bottom, tocolor(255, 20, 20), 1, true ) -- Left
		dxDrawLine ( left, bottom, right, bottom, tocolor(255, 20, 20), 1, true ) -- Bottom
		dxDrawLine ( right, top, right, bottom, tocolor(255, 20, 20), 1, true ) -- Right
	end
end

addEventHandler ( "onClientGUIClick", guiRoot, 
	function()
		if source == scoreGrid then
			selectedRowText = guiGridListGetSelectedText(scoreGrid)
		end
	end
)

-- detecção do clique nas colunas
addEventHandler( "onClientClick", root,
	function ( button, state )
		if button == "left" and state == "up" and not (isMainMenuActive()) and scoreGrid then
			for i=1, guiGridListGetColumnCount( scoreGrid ) do
				local left = columns[i][1]
				local top = columns[i][2]
				local right = columns[i][3]
				local bottom = columns[i][4]
				if isMouseInPosition( left, top, right-left, bottom-top ) then
					onColumnClick( i )
					break
				end
			end
		end
	end
)

-- essa função é chamada quando uma coluna for clicada,
-- o parâmetro 'id' é o índice da tabela correspondente à coluna
local d = { "Ascending", "Descending" }
function onColumnClick( id )

	outputChatBox( "@onColumnClick: #" .. tostring(id) )
	lastClickedColumn = id
	if lastClickedColumn ~= id then
		columns[lastClickedColumn].dir = nil
		columns[id].dir = d[1]
		guiSetProperty( scoreGrid, "SortDirection", d[1] )
	else
		local direction = (columns[id].dir == d[1]) and d[2] or d[1]
		guiSetProperty( scoreGrid, "SortDirection", direction )
		columns[id].dir = direction
	end
	if id == ratio_column then -- coluna ratio
		scoreInfo( columns[id].dir )
	else
		guiSetProperty(scoreGrid, "SortColumnID", id )
	end
end

-- funções úteis
function isMouseInPosition ( x, y, width, height )
	if ( not isCursorShowing( ) ) then
		return false
	end
    local sx, sy = guiGetScreenSize ( )
    local cx, cy = getCursorPosition ( )
    local cx, cy = ( cx * sx ), ( cy * sy )
    if ( cx >= x and cx <= x + width ) and ( cy >= y and cy <= y + height ) then
        return true
    else
        return false
    end
end

function guiGridListGetSelectedText(gridList)
    local selectedItem = guiGridListGetSelectedItem(gridList)
    if (selectedItem) then
        local text = guiGridListGetItemText(gridList, selectedItem, 1)
        if (text) and not (text == "") then
            return text
        end
    end
    return false
end

 

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.