in

C1 Community

ComponentOne Community is a free source for developers and help authors to collaborate and communicate.

Printing problem with custom OwnerDraw and GetMergedRange

Last post 11-12-2007 9:27 AM by Wolfgang Knauf. 5 replies.
Page 1 of 1 (6 items)
Sort Posts: Previous Next
  • 11-08-2007 11:05 AM

    Printing problem with custom OwnerDraw and GetMergedRange

    Hello,

    I have a problem with printing a grid. First, here is a print screen example:


     

    I have a custom designed grid, with grid's DrawMode set to DrawModeEnum.OwnerDraw, implemented OwnerDrawCell and overriden GetMergedRange method. GetMergedRange takes care of merging together appropriate cells (where color stripes run), and OwnerDrawCell takes care of drawing the bitmaps and text. Text is drawn in the first of the merged cells, and stretches accross contiguous merged cells. For displaying, everything goes well.

    The problem is with printing. First, I used C1FlexGrid's own PrintGrid() method. The printscreen of the print preview looks like that:

     

    The design, colors, bitmaps, everything looks OK, except for text, which repeats in every merged cells, and is cut at the end of every cell.

    I then tried and used C1FlexGridPrintable, which is derived from C1FlexGrid and implements some printing methods. So I used PrintPreview() method. The result was following:

     Very ugly design and no bitmaps and text whatsoever. So I prefer to stick with C1FlexGrid's own PrintGrid() method, which seems to be quite ok, except for the text.

    Do you have any idea what went wrong here? How is it possible that screen image differs from print preview image? I won't include OwnerDrawCell and GetMergedRange methods here, because they are a bit long.

     
    Thanks.
     

  • 11-09-2007 5:01 AM In reply to

    Re: Printing problem with custom OwnerDraw and GetMergedRange

    Hi ! 

    How did you initialize the PrintInfo of your C1FlexGridPrintable ? There are some settings required to make the printout look like the grid on screen:

    //Wrap like cell:
    c1FlexGridPrintable.PrintInfo.WrapText = WrapTextEnum.LikeCell;
    //Do not fill anything:
    c1FlexGridPrintable.PrintInfo.FillAreaWidth = FillEmptyEnum.None;
    //RowHeight like grid:
    c1FlexGridPrintable.PrintInfo.VarRowHeight = RowHeightEnum.LikeGrid
    //Do not fit grid on one page (no scaling of columns):
    c1FlexGridPrintable.PrintInfo.PageBreak = PageBreaksEnum.OnColumn;

     

    For the OwnerDrawn cells: could you post the code of your OwnerDrawCell handler ?

    C1FlexGridPrintable calls it this way:
          if (this.DrawMode == DrawModeEnum.OwnerDraw)
          {
            CellStyle s = this.GetCellStyleDisplay(row, col);
            OwnerDrawCellEventArgs e = new OwnerDrawCellEventArgs(this, OwnerDrawGraphics, row, col, s, rc, str, img);
            this.OnOwnerDrawCell(e);
            if (!e.Handled)
            {
              str = e.Text;
              img = e.Image;

              if (e.Style != null)
                cs = e.Style;
            }
          }
    In your screenshot, it seems that the cell image (which is probably larger than the cell) is started in each cell of the merged range, which seems to be wrong. But "CreateTableCell" should create the image only for the first cell of a merged range. Strange problem... I fear you have to do some debugging yourself, maybe you find a bug in the C1FlexGridPrintable.

     

    Best regards


    Wolfgang 

  • 11-09-2007 6:15 AM In reply to

    Re: Printing problem with custom OwnerDraw and GetMergedRange

    Wolfgang, thank you for the quick response. First, I would like to say that I prefer FlexGrid's own PrintGrid method, because, as you can see, the output is (apart from known errors) much better - more like the actual printscreen from the application.

    I will try to explain what I do in my code. First, I have a member variable, which contains (calculated) data to tell GetMergedRange which cells should be merged.

    In OwnerDrawCell, I first do:

            CellRange range = grid.GetMergedRange(
              e.Row,
              e.Col);
            int numOfCells = range.c2 - range.c1;

    to acquire the number of cells. I then apply custom styles to cells (not just merged cells, but all other, too), via e.Style property. The main part of code is pasted below.

    First I set what to draw (background and border).

    I create rectangle the size of one cell. The reason I draw bitmaps in every merged cell is that I cannot have bitmaps for every possible merged length. Instead, I have (basically) 3 bitmaps. One for start, one for middle part (which repeats) and one for ending. 

                    e.DrawCell(DrawCellFlags.Background | DrawCellFlags.Border);

                    Point cellPoint = e.Bounds.Location;
                    Rectangle rect = new Rectangle();
                    rect.Location = cellPoint;
                    rect.Width = CellWidth;
                    rect.Height = RowHeight;

                    // everything in the past has the same grey images
                    planStatusID = planDateTo >= DateTime.Today.Date
                                     ? (int)planRow.PlanStatusID
                                     : Const.NullID;

                    if (planDateTo > m_StartDate.AddDays(GridLength - 1) ||
                        planDateTo > currentDate.AddDays(numOfCells))
                    {
                      numOfCells++;
                    }

                    if (planDateFrom == currentDate)
                    {

     

    // here the starting bitmap is drawn at the beginning of merged cells: 

                      e.Graphics.DrawImage(
                        m_PlanStatusStartBitmap[planStatusID],
                        rect);

                      // if previous dateTo matches current dateFrom and plan types also match,
                      // then draw ending image for previous plan
                      if (planDateFrom == previousPlanDateTo &&
                          m_PlanPlanTypeEnum == m_PreviousPlanPlanTypeEnum)
                      {
                        e.Graphics.DrawImage(
                          m_PlanStatusEndBitmap[previousPlanPlanStatusID],
                          rect);
                      }

                      numOfCells--;
                      rect.X += CellWidth;
                    }

                    for (int nMiddle = 0; nMiddle < numOfCells; nMiddle++)
                    {
                      if (nMiddle > 0)
                      {
                        rect.X += CellWidth;
                      }

    // here the code iterates through merged length and draws "middle" bitmap 

     

                      e.Graphics.DrawImage(
                        m_PlanStatusMiddleBitmap[planStatusID],
                        rect);
                    }

                    if (planDateTo <= m_StartDate.AddDays(GridLength - 1))
                    {
                      if (planDateTo > currentDate &&
                          numOfCells > 0)
                      {
                        rect.X += CellWidth;
                      }

    // and at the end, "ending" bitmap is drawn 

     

                      e.Graphics.DrawImage(
                        m_PlanStatusEndBitmap[planStatusID],
                        rect);
                    }

    // then, caption is written in merged cells. I will supply this method below. 

                    if (numOfCells > 0)
                    {
                      DrawBookingCaption(
                        e,
                        planRow,
                        planStatusID,
                        numOfCells);
                    }

     

     // basically, what I do here is, I create rectangle the size of merged cells, and the caption is written (drawn) into that particular cell.

     

        /// <summary>
        /// Draws booking caption.
        /// </summary>
        /// <param name="p_EventArgs">Inherited event args</param>
        /// <param name="p_PlanRow">Booking plan record</param>
        /// <param name="p_CorrectedPlanStatusID">Corrected plan status ID</param>
        /// <param name="p_NumOfCells">Number of cells</param>
        private void DrawBookingCaption(
          OwnerDrawCellEventArgs p_EventArgs,
          BookingPlanDataSet.BookingPlanTRow p_PlanRow,
          int p_CorrectedPlanStatusID,
          int p_NumOfCells)
        {
          StringFormat sf = new StringFormat();
          sf.Alignment = StringAlignment.Near;
          sf.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.NoClip;
          sf.LineAlignment = StringAlignment.Near;
          sf.Trimming = StringTrimming.EllipsisCharacter;

          string caption;

          if (p_PlanRow.PlanStatusID > 4)
          {
            caption = p_PlanRow.BookingCaption;
          }
          else
          {
            caption = string.Format(
              "{0} ({1}€)",
              p_PlanRow.BookingCaption,
              string.Format(
                "{0:N2}",
                CalculatePrice(p_PlanRow)));
          }

          SizeF sz = p_EventArgs.Graphics.MeasureString(
            caption,
            grid.Font,
            p_PlanRow.DateFrom < m_StartDate
              ? p_NumOfCells * CellWidth
              : (p_NumOfCells + 1) * CellWidth - BookingCaptionOffset,
            sf);

          RectangleF rf = new RectangleF();
          rf.X = p_PlanRow.DateFrom < m_StartDate
                   ? p_EventArgs.Bounds.X
                   : p_EventArgs.Bounds.X + BookingCaptionOffset;
          rf.Y = p_EventArgs.Bounds.Y + (p_EventArgs.Bounds.Height - sz.Height) / 2;
          rf.Width = sz.Width;
          rf.Height = sz.Height;

          p_EventArgs.Graphics.DrawString(
            caption,
            grid.Font,
            p_PlanRow.PlanStatusID == 6 && p_CorrectedPlanStatusID != Const.NullID
              ? Brushes.White
              : Brushes.Black,
            rf,
            sf);
        }

     

     

    I hope you got better picture of the problem. I have to merge cells, because I don't know how to write captions across  multiple cells, if they are not merged. Also, I don't know how to draw bitmaps (of variable cell lengths), other than combining them like I do. Do you have any other idea how to accomplish all that?

    Thanks! 

  • 11-09-2007 8:44 AM In reply to

    Re: Printing problem with custom OwnerDraw and GetMergedRange

    Hmmm, could you try to create one image for the whole merged range ? I think the C1FlexGridPrintable makes the top left cell span the whole merged range, so it should work with one large picture.

    How do you create the merged ranges ? If you use AllowMerging = AllowMergingEnum.Custom, then you need a bugfix in the C1FlexGridPrintable code (see my other code).

    Best regards

    Wolfgang 

  • 11-12-2007 4:51 AM In reply to

    Re: Printing problem with custom OwnerDraw and GetMergedRange

    I create merged ranges in this way:

     

        public CellRange GetMergedRange(
          int p_Row,
          int p_Col,
          bool p_Clip)
        {
          CellRange rg = grid.GetCellRange(
            p_Row,
            p_Col);

          if (p_Row > 0 &&
              p_Col >= AccoColumnCount)
          {
            int key = p_Row * GridLength + p_Col - AccoColumnCount;

            if (m_MergeLength.ContainsKey(key))
            {
              rg.c2 = rg.c1 + m_MergeLength[key];
            }
          }

          return rg;
        }

    I have a collection <int, int>, with key being cell number (first row from 0..N-1, second row from N to 2N-1, etc), and value being number of cells to merge. Collection contains only pairs where merging should occur.

    Wolfgang, I also sent you one private message. Have you read it already?

     

    Tnx 

  • 11-12-2007 9:27 AM In reply to

    Re: Printing problem with custom OwnerDraw and GetMergedRange

    Your "GetMergedRange" should work (if it is implemented in the C1FlexGridPrintable subclass). I think best is to debug through the C1FlexGridPrintable code...

    I did not receive any private message. Did you send it through the forum or by mail ?

    Best regards

    Wolfgang 


     

Page 1 of 1 (6 items)
Contact ComponentOne: 1.800.858.2739 ©1987-2008 ComponentOne LLC All Rights Reserved.