2012-01-13 16 views
5

Esto no parece ser tan simple como yo esperaba:Refrescante wxGrid con contenidos dinámicos

Uso de wxWidgets (2.8 series estable), tengo un wxGrid (no subclase) con un adaptador de datos “” personalizados como una clase derivada de wxGridTableBase.

wxGrid* grid = new wxGrid (this, ID_TABLE); 
grid->SetTable (new TableAdapter (foo, bar, baz)); 
grid->EnableEditing (false); 
sizer->Add(grid, wxSizerFlags (1).Expand()); 

Lo “simple” que no puedo encontrar una manera de actualizar la ventana cuando los cambios subyacentes modelo de datos. Simplemente llamando a wxWindow :: Update (pGrid->Update()) es aparentemente insuficiente para que la grilla llame a la implementación subyacente de wxGridTableBase.

wxGrid* const grid = (wxGrid* const) FindWindow (ID_TABLE); 
if (NULL != grid) { 
    grid->Update(); 
    grid->AutoSizeColumns(); 
} 

En particular, esta rejilla está actuando como una lista, y tendrá filas añadirse y eliminarse de ella de forma asíncrona, por el mismo o (potencialmente) otro proceso - es una lista de datos compartida que puede ser actualizado por cualquiera de varios sistemas en red. La grilla/lista en sí es efectivamente de solo lectura; otros controles se utilizan para agregar y eliminar elementos, y cada fila tiene un atributo de tipo booleano que también se puede alternar.

Parece que las filas nuevas no se agregan a la vista, y al eliminar filas se generarán SEGV intermitentes en el código de dibujo wx.

Debido al mecanismo dinámico/asíncrono actualización, estoy esperando para evitar tener que eliminar y volver a añadir la red a la ventana constantemente, como estoy seguro de que va a causar todo tipo de parpadeo y maldad ... por lo tanto, recurriré a intentar algo así como fuerza bruta, si es absolutamente necesario, pero preferiría evitarlo.

Desafortunadamente, a pesar de estar marcado como la "versión estable", la documentación de wxGrid parece consistir principalmente en Yet to be written etiquetas.

Actualizado: Estoy empezando a sospechar que se trata de un problema de diseño de contenedor. Al dibujar la cuadrícula, la parte inferior de la cuadrícula (última fila) puede solaparse tanto con el marco wxStaticBox alrededor de su sección de la ventana wxFrame, como con parte de la línea de estado del marco. Agregar y eliminar filas no parece obligar a un nuevo diseño del contenedor; Estoy experimentando tratando de llamar al Layout y similares. Idealmente, esto debería ser una región de desplazamiento, pero el wxGrid debería estar "restringido" dentro de su Sizer.

El diseño consta, efectivamente, de una caja estática, que contiene una caja vertical, el primer elemento de los cuales es una caja horizontal de botones, a continuación, la red, como así:

--[ Static Box ]------------------------ 
    |          | 
    | [Button] [Button] [Button]    | 
    |          | 
    | ----------------------------------- | 
    | |  | A  | B | C | | 
    | |-----------------------------------| | 
    | | 1 | 1a  | 1b | 1c | | 
    | ----------------------------------- | 
    |          | 
    ---------------------------------------- 

Desafortunadamente, política de la empresa me prohíbe publicar capturas de pantalla :-(

Si es importante, esto es (actualmente) wxGTK-2.8.12 en Fedora 16 (x86_64), aunque estoy viendo un comportamiento idéntico en CentOS5/RHEL5 usando el EPEL (Fedora) paquetes.

+0

(para repetir lo que mencioné a continuación, donde alguien puede encontrarlo :) Me temo que nunca encontré una mejor solución, y nos movimos a la serie beta de wxWidgets 2.9, luego dejé ese trabajo, entonces ... lo que tengo debajo efectivamente funcional, pero no muy agradable. : -/ – BRFennPocock

Respuesta

6

Después de mucha experimentación, parece que la forma “correcta” para forzar una actualización más o menos así:

bool 
CDynamicWxGridTable::AppendRows(const size_t IGNORED _) 
{ 
    wxGrid *grid = GetView(); 

    if (pGrid != NULL) 
    { 
     const int iNumRecords = GetNumberRows(); 
     const int iGridRows = grid->GetNumberRows(); 
     const int iNeedRows = iNumRecords - iGridRows; 

     if (iNeedRows) 
     { 
     grid->BeginBatch(); 
     grid->ClearSelection(); 

     if (grid->IsCellEditControlEnabled()) 
     { 
      grid->DisableCellEditControl(); 
     } 

     { 
      wxGridTableMessage pop(this, 
       wxGRIDTABLE_NOTIFY_ROWS_DELETED, 
       0, iGridRows); 
      grid->ProcessTableMessage(pop); 
     } 
     { 
      wxGridTableMessage push(this, 
       wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 
       iNumRecords); 
      grid->ProcessTableMessage(push); 
     } 
     grid->AutoSize(); 
     grid->ForceRefresh(); 
     grid->EndBatch(); 
     } 
    } 

    return true; 
} 

bool 
CDynamicWxGridTable::DeleteRows(const size_t IGNORED pos, 
     const size_t IGNORED rows) 
{ 
    return AppendRows(0); 
} 

Estos se llaman durante mi (5 Hz) rutina de actualización por el acaparamiento de grid y llamando su Método ->AppendRows(1), que a su vez llama al miembro wxTableBase -derivado de la clase derivada ::AppendRows.

Desafortunadamente, como dibujo de registros asincrónicos actualizados dinámicamente, el sistema de almacenamiento en caché de wxGrid todavía me "pelea" en cuanto a atributos de filas (si una fila cambia, por ejemplo, su valor GetAttr debe cambiar, no lo hace) No se actualice de forma dinámica, ya que lo anterior solo prueba el número de filas que debería haber versus el número de filas que realmente existen). Sin embargo, este es un error relativamente menor, y espero superarlo por otros medios.

La parte "crítica" parece sintetizar los mensajes eliminar/anexar filas al sistema wxGridTable a través de ProcessTableMessage ... sin los cuales, la memoria caché wxGrid parece no advertir los cambios en el tamaño de la tabla.

Por cierto, se bloquea debido a que pierden filas se aliviaron al poner guardias en el método ::GetValue(const int row, const int column) para comprobar si hay valores válidos:

if (row < 0 || row > GetNumberRows()) { return L"×"; } 
if (col < 0 || col > LAST_COLUMN) { return L"×"; } 

Estos valores “x” no siempre parecen mostrar, después de añadir el la lógica loca de inyección de mensajes anterior, sin embargo.

+1

Gran respuesta. No necesita llamar a ForceRefresh() dentro de su bloque BeginBatch ... EndBatch, porque no hace nada. De hecho, lo que hace ForceRefresh es: {BeginBatch(); EndBatch();} – Wacek

+0

Olvidé que esto estaba aquí, me temo que ya no trabajo allí, así que no puedo probarlo, el truco anterior funcionó, pero terminamos tropezando con la versión "beta casi estable" debido a este y otros problemas con los wxWidgets estables. Sin embargo, ¡gracias por la elucidación! – BRFennPocock

+0

En respuesta a su pregunta anterior, está perfectamente bien aceptar su propia respuesta, si esa fue la solución que terminó usando. Alentamos a las personas a responder a su propia pregunta si se les ocurre una solución diferente a la sugerida por los demás, por lo que no hay problema para aceptar esa solución. Lo he hecho yo mismo. –

1

wxGrid :: ForceRefresh()

Causa el repintado inmediato de la red. Use esto en lugar de wxWindow :: Refresh habitual.

+0

Desafortunadamente, esto no parece funcionar. :-( – BRFennPocock

1

Desafortunadamente, parece que una llamada a pGrid->Update() no será suficiente.La llamada a esa función llamará realmente al wxWindow::Update, que vuelve a pintar el área invalidada de la ventana, junto con todo su elemento recursivo, es posible que no funcione correctamente.

En cambio, lo que desea llamar es wxGrid::ForceRefresh() como se detalla en la documentación here. La documentación dice

Causa el repintado inmediato de la red.

Utilice esto en lugar del habitual wxWindow::Refresh().

Lo que es interesante, sin embargo, es que si nos fijamos en el ejemplo rejilla en el proyecto de muestras suministrado con wxWidgets, utilizan simplemente wxGrid::Refresh.

He usado wxWidgets (C++) y wxPython, y para mi wxGrid utilizo ForceRefresh. Se puede encontrar un ejemplo de su uso here. Si bien es wxPython, no parecía encontrar un ejemplo en línea usando la versión C++, sin embargo, habiendo utilizado ambas bibliotecas, puedo decir que ambas se usan de la misma manera.

+0

Desafortunadamente, esto no parece funcionar. :-( – BRFennPocock

Cuestiones relacionadas