Улучшение блока управления скоростью (C ++ - CLI WinForms) - PullRequest
0 голосов
/ 23 декабря 2010

Я сделал элемент управления в c ++, чтобы позволить пользователю выбирать позицию в неправильном поле с различными позициями, некоторые из которых заблокированы, некоторые заполнены, с такими характеристиками:

  • Может создавать несколько столбцов в нескольких строках (не одно и то же, поэтому первая строка с 3 столбцами может быть, вторая - с 1, а третья - с 5)

  • Различные состояниякаждая позиция: заблокирована, заполнена, пуста, выбрана (поэтому она может иметь некоторые из них одновременно: заблокирована и пуста, заблокирована и заполнена, пуста и выбрана)

  • Пользователь можетвыберите одну или несколько позиций

  • Имеются текстовые подсказки и различные фоновые изображения для каждой заполненной или пустой позиции.

  • Контекстное меню для добавления / удалениястроки / столбцы.

  • Заголовки строк и столбцов, числовые / буквенно-цифровые, по возрастанию / по убыванию.

Структура элемента управления Container->(nRows x RowClass) и RowClass -> (nCols x ColumnClass).Каждый столбец содержит TableLayoutPanel, поэтому я могу имитировать застрявшие и поднятые эффекты.

Просматривая различные темы в Интернете, я нашел несколько идей, и улучшения, которые я сделал для скорости, в основном заключаются в SuspendDrawing с SendMessage (для созданияи измените размер всех строк и столбцов перед их рисованием), дважды буферизуя каждый элемент управления и добавляя метод BeginEdit / EndEdit в контейнер, который SuspendDrawing и блокирует изменение размеров строк и столбцов при создании строк и столбцов (и то же самое для каждого RowClass).

Он работает не так плохо с относительно небольшими блоками, скажем, 20 строк x 20 столбцов, но когда он имеет 40 строк x 30 столбцов (1.200 TableLayoutPanel's), он работает очень медленно даже на быстром компьютере.

Я также пытался использовать одну TableLayoutPanel (с необходимым количеством столбцов) для RowClass, но проблема в том, как нарисовать границы, чтобы выделить каждый столбец отдельно, всплывающие подсказки и фоновое изображение для каждой ячейки.

Итак, вопрос:Могу ли я попробовать какие-нибудь улучшения?

Я думал, что такие стратегические игры, как warcraft или аналогичные, имеют хорошую скорость на экране с тысячами графики и вычислений, но я не профессиональный программист, такЯ не знаю, какой может быть технология, и если это правильный путь ..

Может быть, это может быть что-то вроде изображения с рядом изображений или что-то отличное от класса классов классов,но я понятия не имею ...

Вероятно, это проблема дизайна, поэтому любая идея о том, как создать быстрый элемент управления с этими спецификациями, будет отличной.

В любом случае, спасибо за чтение моеговопрос, любые комментарии будут приветствоваться!Miguel

Ответы [ 3 ]

0 голосов
/ 23 декабря 2010

Чистых решений для этого не существует, вам придется отказаться от TLP. Элемент управления - это очень слишком дорогой объект, любая форма, в которой их более ста, будет высасывать грязь.

Сначала рассмотрим встроенные типы элементов управления, которые поддерживают отображение в виде сетки. ListView с View = Подробности для нередактируемых сеток, DataGridView для редактируемых. Если это не соответствует вашему счету, то вам придется сделать свой собственный. Ключевыми вещами, которые вам нужно реализовать, является метод OnPaint () для рисования визуального вида элемента управления и OnMouseDown или OnClick для тестирования попаданий и реализации поведения.

0 голосов
/ 24 декабря 2010

Вот часть кода (весь код действительно огромный), где выполняются некоторые вычисления ..

В ControlClass ::

    void BeginEdit(int nFilas) {
        if (!_editando) {

            if (_muestraBarraProgreso) {
                this->BarraProgreso->Value = 0;
                this->BarraProgreso->Visible = true;
                }

            _editando = true;
            _lastEdit = nFilas;
            this->Cursor = Cursors::WaitCursor;
            this->Refresh();
            SendMessageClass::SuspendDrawing();
            }
        };

    /// <summary>Provoca se realicen los cambios visuales no realizados desde que se
    /// llamó a BeginEdit, como this->Controls.Add(...), Ajustar los tamaños de los controles, ...</summary>
    void EndEdit(void) {
        if (_editando) {
            int f;
            _editando = false;

            AjustaHeaders();
            AjustaTamaños(); //Provoca el ajuste de las filas sin ajustar las columnas

            //Esto lo hago para minimizar el número de AjustaTamaños()
            for (f=_lastEdit; f<_nFilas; f++)
                _fila[f]->EndEdit(false); //Provoca el ajuste de las columnas

            this->MuestraBarraProgreso = false;
            this->Cursor = Cursors::Default;
            SendMessageClass::ResumeDrawing();
            }
        };

    void AjustaTamaños(void) {
        if (!_editando && _nFilas>0) {
            int topOffset = 0, leftOffset = 0, bottomOffset = 0;

            if (_showColumnHeaders) topOffset = this->tlpColumnHeaders->Height;
            if (_showRowHeaders) leftOffset = this->tlpRowHeaders->Width;
            if (_muestraEstado) bottomOffset = this->EstadoRecipiente->Height;

            int hOffset = leftOffset + 2;
            int vOffset = topOffset + bottomOffset + 2;

            int i, j = 0, stp;

            if (_varsCom->ordenFilas == TipoOrdenFilas::Descendiente) {
                j = 0; stp = 1; 
                }
            else {
                j = _nFilas-1; stp = -1;
                }

            for (i=0; i<_nFilas; i++) {
                _fila[j]->Left = hOffset;
                _fila[j]->Width = this->Width - hOffset;
                _fila[j]->Top = (_nFilas - 1 - i) * (this->Height - vOffset) / _nFilas + topOffset;
                _fila[j]->Height = (this->Height - vOffset) / _nFilas;
                j+=stp;
                }
            }
        };

в FilaClass:

    /// <summary>Provoca que no se realicen los cambios visuales hasta que se llame EndEdit</summary>
    void BeginEdit(void) {
        if (!_editando) {
            _editando = true;
            _lastEdit = _nColumnas;
            SendMessageClass::SuspendDrawing();
            }
        };
    /// <summary>Provoca se realicen los cambios visuales no realizados desde que se
    /// llamó a BeginEdit, como this->Controls.Add(...), Ajustar los tamaños de los controles, ...</summary>
    void EndEdit(bool resumirDrawing) {
        if (_editando) {
            _editando = false;

            AjustaTamaños();

            for (int c=_lastEdit; c<_nColumnas;c++)
                _columna[c]->EndEdit(resumirDrawing);

            if (resumirDrawing) SendMessageClass::ResumeDrawing();
            }
        };

    void AjustaTamaños(void) {
        if (!_editando) {
            int j, stp;

            if (_varsCom->ordenColumnas == TipoOrdenColumnas::IzquierdaDerecha) {
                j = 0; stp = 1;
                }
            else {
                j = _nColumnas-1; stp = -1;
                }

            for (int i=0; i<_nColumnas; i++) {
                _columna[j]->Width = this->Width / _nColumnas;
                _columna[j]->Left = i * this->Width / _nColumnas;
                _columna[j]->Top = 0;
                _columna[j]->Height = this->Height;
                j+=stp;
                }
            }
        };

в ColumnaClass:

    void BeginEdit(void) {
        _editando = true;
        SendMessageClass::SuspendDrawing();
        };
    void EndEdit(bool resumirDrawing) {
        if (_editando) {
            _editando = false;
            _CambiaEstado = _estado;
            if (resumirDrawing) SendMessageClass::ResumeDrawing();
            }
        };
internal:       
    /// <summary>Obtiene o establece el estado de la posición sin activar el evento ColumnaChange</summary>
    property EstadoColumna _CambiaEstado {
        EstadoColumna get() { return _estado; }
        void set(EstadoColumna value) {
            _estado = value;
            if ( (_varsCom->bloquearLlenas && ((value & EstadoColumna::llena) == EstadoColumna::llena)) || 
                 (_varsCom->bloquearVacias && ((value & EstadoColumna::llena) != EstadoColumna::llena)) ) {
                if ((_estado & EstadoColumna::seleccionada) == EstadoColumna::seleccionada)
                    _estado = (EstadoColumna) (_estado ^ EstadoColumna::seleccionada);
                _estado = (EstadoColumna) (_estado | EstadoColumna::bloqueada);
                }
            else {
                if ((_estado & EstadoColumna::bloqueada) == EstadoColumna::bloqueada)
                    _estado = (EstadoColumna) (_estado | EstadoColumna::bloqueada);
                }

            if (!_editando) {
                ActualizaEstado();
                ActualizaToolTip();
                }
            }
        };

    /// <summary>Actualiza la visualización de la posición leyendo de nuevo los parámetros</summary>
    void ActualizaEstado(void) {
        if (!_editando && _varsCom->estilo) {
            this->ColumnaCtl->BackColor = _varsCom->estilo->GetEstilo[(int) _estado]->colorFondo;
            this->ColumnaCtl->CellBorderStyle = _varsCom->estilo->GetEstilo[(int) _estado]->bordeCelda;
            this->ColumnaCtl->BackgroundImageLayout = _varsCom->imageLayout;

            if (this->Estado[EstadoColumna::llena])
                this->ColumnaCtl->BackgroundImage = _varsCom->imagenLlena;
            else if (this->Estado[EstadoColumna::vacia])
                this->ColumnaCtl->BackgroundImage = _varsCom->imagenVacia;
            }
        };

    /// <summary>Actualiza los textos del ToolTipText de la posición</summary>
    void ActualizaToolTip(void) {
        if (!_editando && _varsCom->etiquetas) {
            String^ sTmp = "";
            int __tmp__ = 0;

            if (_varsCom->tipoHeaderFilas == TipoHeader::Numerica)
                sTmp = _varsCom->etiquetas->Fila + ": " + _nombreFila;
            else if (System::Int32::TryParse(_nombreFila, __tmp__))
                sTmp = _varsCom->etiquetas->Fila + ": " + gcnew String((wchar_t) ('A' + __tmp__ - 1), 1);
            else 
                sTmp = _varsCom->etiquetas->Fila + ": " + _nombreFila;

            if (_varsCom->tipoHeaderColumnas == TipoHeader::Numerica)
                sTmp += ", " + _varsCom->etiquetas->Columna + ": " + _posicion + "\n";
            else
                sTmp += ", " + _varsCom->etiquetas->Columna + ": " + gcnew String((wchar_t) ('A' + _posicion - 1), 1) + "\n";

            if (_nombre != "") {
                if ((_estado & EstadoColumna::llena) == EstadoColumna::llena)
                    sTmp += _varsCom->etiquetas->Posicion + ": " + _nombre + "\n";
                else
                    sTmp += _varsCom->etiquetas->PosicionVacia + ": " + _nombre + "\n";
                }

            if ((_estado & EstadoColumna::llena) == EstadoColumna::llena) sTmp += "Ocupada, ";
            else sTmp += "Vacía, ";

            if ((_estado & EstadoColumna::seleccionada) != EstadoColumna::vacia) sTmp += "Seleccionada";
            else sTmp += "Sin seleccionar";

            this->ToolTip1->ShowAlways = false;
            this->ToolTip1->SetToolTip(this->ColumnaCtl, sTmp);
            this->ToolTip1->ShowAlways = true;
            }
        };

Я думаю, что это большая часть вычислений .. Немного без комментариев, и на испанском, но любая помощь будет действительно полезна!В любом случае, спасибо!

0 голосов
/ 23 декабря 2010

Видеоигры выгружают графические представления по крайней мере на GPU (которые созданы именно для этой цели). Я не думаю, что представление коробок является узким местом, скорее расчеты / шаги, чтобы туда добраться. Либо опубликуйте свой код / ​​фрагмент кода, либо объясните, как вы используете алгоритмы, потому что из-за плохого алгоритма ваша программа будет работать очень медленно при увеличении входных данных - взгляните на сложности вычислений, что поднимается курсами алгоритмов. http://en.wikipedia.org/wiki/Computational_complexity_theory

...