Приложение STUpload. Отображение данных приложения

   
На этом шаге мы рассмотрим отображение данных в приложении STUpload.

   
Теперь все готово для реализации графического отображения данных, относящихся к выбранной ценной бумаге.
Сначала нужно определить размер документа, чтобы класс CScrollView правильно отображал полосы прокрутки.
После загрузки очередного текстового файла количество данных приложения STUpload увеличивается,
однако размеры представления всегда остаются неизменными - в нем отображается только одна диаграмма.
Этот размер соответствует печатной странице с альбомной ориентацией.

  • Установка размеров прокрутки для приложения STUpload.
  • На вкладке ClassView раскройте узел CSTUploadView.
  • Дважды щелкните значок OnInitialUpdate(), чтобы отредактировать функцию.
  • Измените строки
        sizeTotal.cx = sizeTotal.cy = 100; 
        SetScrollSizes(MM_TEXT, sizeTotal);
    

    следующим образом:

       sizeTotal.cx = 1100;
       sizeTotal.cy = 850;
       SetScrollSizes(MM_LOENGLISH, sizeTotal);
    

   
Теперь изаменим функцию CView::OnDraw(). Эта функция считывает из файла данные, относящиеся к
определенной ценной бумаге, и помещает их во временный массив. На основе этих данных вычисляются масштабы
для оси времени (ось х) и оси цен (ось у). Данные представлены в виде ломаной линии, позволяющей
оператору легко находить ошибки. Обратите внимание, как в приведенном ниже коде выполняется вывод данных
в контекст устройства средствами MFC-классов инструментов рисования и графических GDI-функций.

  • Реализация метода OnDraw().
  • На вкладке ClassView раскройте узел CSTUploadView.
  • Дважды щелкните значок OnDraw(), чтобы отредактировать функцию.
  • Замените весъ метод кодом, приведенным ниже:
    void CSTUploadView::OnDraw(CDC* pDC)
    {
      CSTUploadDoc* pDoc = GetDocument();
      ASSERT_VALID(pDoc);
    
      // Сохраняем текущее состояние контекста устройства
      int nDC = pDC->SaveDC();
      const CStockDataList & pData = pDoc->GetDocList();
    
      // Создаем небольшой массив для 
      // хранения записей текущей ценной бумаги. 
      // Он нужен для индексного доступа к данным. 
      CArray< CStockData, CStockData & > arrFundData;
      POSITION pos = pData.GetHeadPosition();
      while( pos )
      {
        CStockData sd = pData.GetNext( pos );
        if( sd.GetFund() == pDoc->GetCurrentFund() )
            arrFundData.Add( sd );
      }
    
      int nPrices = arrFundData.GetSize();
      if( nPrices == 0 ) return; 
    
      // Константы для размеров (в единицах устройства)
      const int AXIS_DIVIDER_LENGTH = 6;
      const int AXIS_FONT_HEIGHT = 24;
      const int HEADING_FONT_HEIGHT = 36;
    
      // Создаем шрифт для меток на осях
      CFont AxisFont;
      if( AxisFont.CreateFont( AXIS_FONT_HEIGHT, 0, 
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, FF_ROMAN, 0 ))   
          pDC->SelectObject( &AxisFont );
      else
      {
          AfxMessageBox( "Unable to create Axis font" );
          return;
      }
    
      CPen AxisPen;
      if( AxisPen.CreatePen( PS_SOLID, 1, RGB(0,0,0) ) )    
        pDC->SelectObject( &AxisPen );
      else
      {
          AfxMessageBox( "Unable to create Axis Pen" );
          return;
      }
    
      // Массив координат диаграммы
      CArray< CPoint, CPoint& > CoordArray;
      for( int i = 0; i < nPrices; i++ )
        CoordArray.Add( CPoint( 0, 0) );
    
      // Устанавливаем начало области просмотра 
      // в нижний угол окна
      CPoint ptBottomLeft( 0, -850 );
      pDC->LPtoDP( &ptBottomLeft );
      pDC->SetViewportOrg( ptBottomLeft );
    
      // Базовые координаты осей
      const CPoint ORIGIN(100, 100);
      const CPoint Y_EXTENT( ORIGIN.x, ORIGIN.y + 650);
      const CPoint X_EXTENT(ORIGIN.x + 900, ORIGIN.y);
    
      // Оси рисования
      pDC->MoveTo( Y_EXTENT );
      pDC->LineTo( ORIGIN );
      pDC->LineTo( X_EXTENT );
    
      int nLabelPos = Y_EXTENT.y + ((ORIGIN.y - Y_EXTENT.y) / 2);
      pDC->TextOut( ORIGIN.x - 50, nLabelPos, '$' ); 
    
      // Разбиваем ось x на число записей для цен,
      // взятых из файла
      int nXIncrement = (X_EXTENT.x - ORIGIN.x) / nPrices;
      double nMaxPrice = 0;
      double nMinPrice = 0;
    
      for( i = 0; i < nPrices; i++ )
      {
        int xPoint = (ORIGIN.x + (i * nXIncrement));
        CoordArray[i].x = xPoint;
    
        pDC->MoveTo( xPoint, ORIGIN.y );
        pDC->LineTo( xPoint, ORIGIN.y + AXIS_DIVIDER_LENGTH );
    		
        COleDateTime aDate = arrFundData[ i ].GetDate();
        double aPrice = arrFundData[ i ].GetPrice();
    
        nMaxPrice = max( nMaxPrice, aPrice );
        nMinPrice = nMinPrice == 0 ? 
        nMaxPrice : min( nMinPrice, aPrice );
    
        CString strDate = aDate.Format( "%m/%d/%y" ); 
    		
        if( i == 0 || i == (nPrices-1) )
          pDC->TextOut( xPoint-2, ORIGIN.y - AXIS_FONT_HEIGHT / 2, strDate );
        else
        {
            CString strDay = strDate.Mid( strDate.Find( '/' ) + 1);
            strDay = strDay.Left( strDay.Find( '/' ) );
            pDC->TextOut( xPoint-6, ORIGIN.y - AXIS_FONT_HEIGHT / 2, strDay );
        }
      }
    
    
      // Устанавливаем для оси y масштаб, основанный на 
      // разнице между максимальной и минимальной ценой 
      nMaxPrice += 2.0;
      nMinPrice -= 1.0;
      int iScale = int(nMaxPrice) - int(nMinPrice);
      int nYIncrement = ( ORIGIN.y - Y_EXTENT.y ) / iScale;
    	
      for( i = 0; i < iScale; i++ )
      {
        int yPoint = (ORIGIN.y - (i * nYIncrement));
        pDC->MoveTo( ORIGIN.x, yPoint);
        pDC->LineTo( ORIGIN.x - AXIS_DIVIDER_LENGTH, yPoint);
        int iCurrentPrice = int(nMinPrice) + i;
        for( int j = 0; j < nPrices; j++ )
        {
          double aPrice = arrFundData[ j ].GetPrice();
          if( aPrice >= double(iCurrentPrice) && 
            aPrice <  double(iCurrentPrice) + 1.0 )
          {
            double dFraction = aPrice - double(iCurrentPrice);
            CoordArray[j].y = yPoint - int(dFraction * double(nYIncrement));
          }
        }
        CString strPrice;
        strPrice.Format( "%d", iCurrentPrice );
        int nTextSize = pDC->GetTextExtent( strPrice ).cx;
        nTextSize += 10;
    		
        pDC->TextOut( ORIGIN.x - nTextSize, yPoint+12, strPrice );
      }
    
      // Отображаем данные из массива CoordArray
      CPen GraphPen;	
      if( GraphPen.CreatePen( PS_SOLID, 1, RGB(255,0,0) ) )  // Красное перо  
      {
        pDC->SelectObject( &GraphPen );
      }
      else
      {
        AfxMessageBox( "Unable to create Graph Pen" );
        return;
      }
    
      // Рисуем диаграмму
      // Отображаем значения цены около вершин диаграммы 
      // (голубым цветом)
      COLORREF crOldText = pDC->SetTextColor( RGB( 0,0,255 ) );
      pDC->MoveTo( CoordArray[0] );
      for( i = 0; i < nPrices; i++ )
      {
        pDC->LineTo( CoordArray[i] );
        CPoint TextPoint;
        if( (i+1) < nPrices )
        {
          if( CoordArray[i+1].y >= CoordArray[ i ].y )
            TextPoint = CoordArray[i] + CPoint( 5, 0 );
          else
            TextPoint = CoordArray[i] + CPoint( 5, AXIS_FONT_HEIGHT );
        }
        else
          TextPoint = CoordArray[i] + CPoint( 5, 0);
    
        CString strPrice;
        strPrice.Format( "%.2f", arrFundData[i].GetPrice() );
        pDC->TextOut( TextPoint.x, TextPoint.y, strPrice  ); 
      }
    
      pDC->SetTextColor( crOldText );
      // Создаем заголовок
      CFont HeadingFont;
      if( HeadingFont.
        CreateFont( HEADING_FONT_HEIGHT, 0, 0, 0, FW_BOLD, 1, 0, 0, 0, 
                 0, 0, 0, FF_ROMAN, 0 ))   
    
        pDC->SelectObject( &HeadingFont );
      else
      {
        AfxMessageBox( "Unable to create Heading Font" );
        return;
      }
    
      CString strHeading = pDoc->GetCurrentFund();
      strHeading += " - Closing Prices ";
      COleDateTime aDate = arrFundData[ 0 ].GetDate();
      strHeading += aDate.Format( "%m/%d/%y" ); 
      strHeading += " to ";
      aDate = arrFundData[ nPrices - 1 ].GetDate();
      strHeading += aDate.Format( "%m/%d/%y" ); 
    
      CSize sizeText = pDC->GetTextExtent( strHeading );
      pDC->TextOut( X_EXTENT.x - sizeText.cx, 
          Y_EXTENT.y + sizeText.cy, strHeading );
    
      // Восстанавливаем первоначальный контекст устройства
      pDC->RestoreDC( nDC );
    }
    
  • Соберите и запустите приложение STUpload. Проверьте правильность загрузки данных. Они должны
    отображаться так, как показано на рисунке 1.


    Рис.1.Приложение STUpload

   
Текст измененного приложения можно взять здесь (62,5 Кб).

   
На следующем шаге мы рассмотрим основные методы класса CButton.



Вы можете оставить комментарий, или Трекбэк с вашего сайта.

Оставить комментарий