2011-10-21 112 views
10

Tengo un QTableWidget y la primera columna contiene números del 1 al 1000. Ahora necesito ordenar la tabla según esta primera columna.¿Cómo ordenar datos en QTableWidget?

estoy usando 'sortItems (int columna, Qt :: AscendingOrder)' la función, pero se muestra como: 1, 10, 100, 1000, 101, 102, ...

Pero Necesito el resultado como: 1, 2, 3, 4 ...., 1000.

Estoy usando el archivo csv para rellenar la tabla. ¿Alguien podría ayudarme a hacer esto?

Respuesta

9

La manera más fácil es probablemente subclasificar QTableWidgetItem y luego implementar el operador < para ser inteligente sobre el hecho de que está ordenando números y no cadenas.

class MyTableWidgetItem : public QTableWidgetItem { 
    public: 
     bool operator <(const QTableWidgetItem &other) const 
     { 
      return text().toInt() < other.text().toInt(); 
     } 
}; 

Entonces, cuando usted está poblando su mesa se puede pasar que las instancias de sus artículos personalizados que saben cómo clasificar correctamente a sí mismos en lugar de los genéricos.

+1

¡Respuesta perfecta! Este código funcionó de manera excelente para mí. – zeFree

+0

Gracias, esto funciona. En las versiones más nuevas de Qt, la firma ha cambiado levemente a 'bool operator <(const QTableWidgetItem y otro) const' – iliis

+0

En serio, si' setData (Qt :: DisplayRole, num) 'no funciona para usted, debe intentar esto . – Wesley

17

Los valores se ordenan como cadenas porque los almacenó como tales en el modelo.

El QVariant puede recordar el tipo original de los datos si se deja que haga la conversión en sí, y se utilizará el operador de comparación de ese tipo al ordenar:

// Get the value from the CSV file as a numeric type 
int valueFromCsvFile = ...; 

// don't do this 
QTableWidgetItem *item = new QTableWidgetItem(QString::number(valueFromCsvFile)); 

// but do this instead 
QTableWidgetItem *item = new QTableWidgetItem; 
item.setData(Qt::EditRole, valueFromCsvFile);  

El editor de célula también se adaptará a el tipo de la QVariant:

  • QSpinBox para int,
  • QDoubleSpinBox para double y float,
  • QDateTimeEdit para QDateTime
  • ...
+0

He usado 'item.setData (Qt :: EditRole, valueFromCsvFile)' y ahora funciona bien. ¡Gracias! – Shyam

+0

@Shyam, ¿por qué no establecer esto como la respuesta aceptada? Tuve problemas con esto porque estaba usando un int largo, y extrañamente el QVariant funcionará con long int largo o int, pero no long int. Casting mi int largo para qlonglong funcionó para mí. –

2

Una manera en que funcionaba en mi situación era

1) antes de llenar la tabla, desactive la clasificación:

table.setSortingEnabled(False) 

2) rellenar las cadenas numéricas con espacios en blanco y hacer que todas las cadenas de la columna tengan la misma longitud:

(' '+numStr)[-4:] 

3) después de llenar la tabla, active clasificar:

table.setSortingEnabled(True) 

Esto fija la fila de clasificación problema y el orden numérico.

2

No sé si la respuesta aceptada solía funcionar, pero con Qt5.1, no es así. Para que funcione, la definición operator< tiene que coincidir con la definición virtual de qtablewidget.h.

Otra adición interesante es ordenar elementos que tienen números, pero comienzan con un signo de moneda ($ o por ejemplo) o terminan con %.

Aquí es el código de actualización:

class TableNumberItem : public QTableWidgetItem 
{ 
public: 
    TableNumberItem(const QString txt = QString("0")) 
     :QTableWidgetItem(txt) 
    { 
    } 
    bool operator <(const QTableWidgetItem &other) const 
    { 
     QString str1 = text(); 
     QString str2 = other.text(); 

     if (str1[0] == '$' || str1[0] == '€') { 
      str1.remove(0, 1); 
      str2.remove(0, 1); // we assume both items have the same format 
     } 

     if (str1[str1.length() - 1] == '%') { 
      str1.chop(1); 
      str2.chop(1); // this works for "N%" and for "N %" formatted strings 
     } 

     double f1 = str1.toDouble(); 
     double f2 = str2.toDouble(); 

    return str1.toDouble() < str2.toDouble(); 
    } 
}; 

A continuación, agregue los elementos que contengan números utilizando algo como esto:

myTableWidget->setItem(row, col, new TableNumberItem("$0")); 

Tenga en cuenta que esta clase debe ser utilizado con sólo números , no ordenará las cadenas correctamente (como también es el caso con la respuesta aceptada).

Cuestiones relacionadas