2017-07-30 85 views
1

我正在顯示參加TDBChart上的電影節目的人數,節目的日期是X軸,人的數量是Y軸。不同電影之間的分割由堆疊列表示。TDBChart X軸不正確/略過的值

我通過爲每部電影創建一個小節系列(動態創建)來實現這一點。但是當我顯示超過兩部電影的數據時,所有日期都不會顯示在X軸上,只會添加第一個系列(電影)的日期。進一步的系列只是擠進了第一輯的日期。

在這裏你只看到幽靈公主的圖表,日期是正確的。 日期範圍選擇器此刻不做任何事情。

這是死神圖表只,日期是正確的 enter image description here

但是當你把它們放在一起收割數據被扔進公主Mononokes日期即使死神不會顯示在幽靈公主的日期。並且Reapers日期完全被省略了。 enter image description here

這是添加系列(電影)的代碼,我也爲該系列動態創建SQL查詢。 qryStatMovieSelection就是所有選中的電影。 我真的不知道如何處理這一個,任何想法?

 DataModule1.qryStatMovieSelection.First; 
     for iCount := 0 to iSelectedMovies - 1 do 
     begin 
     arrQryDateCustomers[iCount] := TADOQuery.Create(Self); 
     With arrQryDateCustomers[iCount] do 
     begin 
      Connection := conCinema; 
      SQL.Clear; 
      SQL.Add(
      'SELECT Movies.MovieID, Name, ShowDate,(SUM(NormalTickets) + SUM(ChildTickets) + SUM(SeniorTickets)) AS SeatsBooked'); 
      SQL.Add('FROM Movies, Invoice, Shows'); 
      SQL.Add('WHERE Invoice.ShowID = Shows.ShowID AND Shows.MovieID = Movies.MovieID'); 
      // MovieID in selected table 
      SQL.Add('AND Movies.MovieID = '+ DataModule1.qryStatMovieSelection.FieldByName('MovieID').AsString); 
      SQL.Add('GROUP BY Movies.MovieID, Name, ShowDate'); 
      Open; 
     end; 

     //create series 
     arrBarSeriesMovies[iCount] := TBarSeries.Create(Self); 
     With arrBarSeriesMovies[iCount] do 
     begin 
      ParentChart := crtStatistics; 
      YValues.ValueSource := 'SeatsBooked'; 
      XValues.DateTime := True; 
      XLabelsSource := 'ShowDate'; 
      DataSource := arrQryDateCustomers[iCount]; 
      MultiBar := mbStacked; 
      Marks.Style := smsValue; 
      Marks.ArrowLength := -20; 
      Color := arrColor[iCount]; 
      Title := DataModule1.qryStatMovieSelection.FieldByName('Name').AsString; 
      Active := True; 
     end; 
     DataModule1.qryStatMovieSelection.Next; 
     end; 
    end 
+0

你可能尋找'MultiBar'的'mbSideAll'風格。 – Victoria

+2

對於那些想玩你的代碼的人來說,這裏是反向工程模式http://sqlfiddle.com/#!5/1d928/5。 – Victoria

+0

這不是mbSideAll,我希望酒吧堆疊,但只有當他們的日期是相同的。否則,他們會與他們自己的約會形成另一個酒吧 – epep

回答

0

我知道你要堆疊同一日期的酒吧,即使他們不符合時間。

問題是TBarSeries堆積在ValueIndex重合,但不在XValue。因此,您應該在該系列中添加一個Null點,該點沒有在某個日期售出的門票在兩個系列中具有相同的點數。

首先,我初始化數據如下:

type TShow = class 
    ShowDate: TDateTime; 
    TotalTickets: Integer; 
end; 

type TMovie = class 
    Title: String; 
    Shows: array of TShow; 
end; 

procedure TForm1.FormCreate(Sender: TObject);  
var movies: array of TMovie; 
begin 
    SetLength(movies, 2); 
    movies[0]:=TMovie.Create; 
    movies[1]:=TMovie.Create; 

    with movies[0] do 
    begin 
    Title:='Princess Mononoke'; 
    SetLength(Shows, 2); 
    Shows[0]:=TShow.Create; 
    Shows[1]:=TShow.Create; 

    Shows[0].ShowDate:=StrToDateTime('14/07/2017 15:00'); 
    Shows[0].TotalTickets:=19; 
    Shows[1].ShowDate:=StrToDateTime('20/07/2017 17:30'); 
    Shows[1].TotalTickets:=5; 
    end; 

    with movies[1] do 
    begin 
    Title:='Reaper'; 
    SetLength(Shows, 2); 
    Shows[0]:=TShow.Create; 
    Shows[1]:=TShow.Create; 

    Shows[0].ShowDate:=StrToDateTime('20/07/2017 15:30'); 
    Shows[0].TotalTickets:=1; 
    Shows[1].ShowDate:=StrToDateTime('23/07/2017 17:30'); 
    Shows[1].TotalTickets:=15; 
    end; 
end; 

然後我算最小和最大日期與此函數在給定的電影:

procedure TForm1.FormCreate(Sender: TObject);  

    procedure MinMaxDates(AMovies: array of TMovie; var MinDate: TDateTime; var MaxDate: TDateTime); 
    var i, j: Integer; 
    begin 
    MinDate:=Trunc(AMovies[0].Shows[0].ShowDate); 
    MaxDate:=Trunc(AMovies[0].Shows[0].ShowDate); 
    for i:=0 to High(AMovies) do 
     for j:=0 to High(AMovies[i].Shows) do 
     begin 
     MinDate:=Min(MinDate, Trunc(AMovies[i].Shows[j].ShowDate)); 
     MaxDate:=Max(MinDate, Trunc(AMovies[i].Shows[j].ShowDate)); 
     end; 
    end; 

var movies: array of TMovie; 
    minDate, maxDate: TDateTime; 
begin 
    // Data initialization here 

    MinMaxDates(movies, minDate, maxDate); 

現在我能想到的這裏有幾個選項。

選項1:你可以在所有系列都minDatemaxDate之間的日期加分,即使沒有門票出售。此選項尊重各條塊之間的距離的比例,並給出細條:

Option 1

procedure TForm1.FormCreate(Sender: TObject);  

    function TicketsAtDate(AMovie: TMovie; ADate: TDateTime): Integer; 
    var i: Integer; 
    begin 
    Result:=0; 
    for i:=0 to High(AMovie.Shows) do 
     if Trunc(AMovie.Shows[i].ShowDate) = ADate then 
     begin 
     Result:=AMovie.Shows[i].TotalTickets; 
     Break; 
     end; 
    end; 

var i, j: Integer; 
    movies: array of TMovie; 
    minDate, maxDate: TDateTime; 
begin 
    // Data initialization here 

    MinMaxDates(movies, minDate, maxDate); 

    for i:=0 to High(movies) do 
    begin 
    //create series 
    With Chart1.AddSeries(TBarSeries) as TBarSeries do 
    begin 
     XValues.DateTime := True; 
     MultiBar := mbStacked; 
     Marks.Style := smsValue; 
     Marks.ArrowLength := -20; 
     Title:=movies[i].Title; 
     j:=0; 
     while (minDate+j<=maxDate) do 
     begin 
     AddXY(minDate+j, TicketsAtDate(movies[i], minDate+j)); 

     if YValue[Count-1] = 0 then 
      SetNull(Count-1); 

     Inc(j); 
     end; 
    end; 
    end; 
end; 

選項2:你可以加點,只有當有一些票在每售出之日起。此選項仍然尊重各條塊之間的距離的比例並給出了寬條:

Option 2

procedure TForm1.FormCreate(Sender: TObject);  

    function AnyTicketSold(AMovies: array of TMovie; ADate: TDateTime): Boolean; 
    var i, j: Integer; 
    begin 
    Result:=False; 
    for i:=0 to High(AMovies) do 
     for j:=0 to High(AMovies[i].Shows) do 
     if (Trunc(AMovies[i].Shows[j].ShowDate) = ADate) and (AMovies[i].Shows[j].TotalTickets > 0) then 
     begin 
      Result:=True; 
      Exit; 
     end; 
    end; 

var i, j: Integer; 
    movies: array of TMovie; 
    minDate, maxDate: TDateTime; 
begin 
    // Data initialization here 

    MinMaxDates(movies, minDate, maxDate); 

    for i:=0 to High(movies) do 
    begin 
    //create series 
    With Chart1.AddSeries(TBarSeries) as TBarSeries do 
    begin 
     XValues.DateTime := True; 
     MultiBar := mbStacked; 
     Marks.Style := smsValue; 
     Marks.ArrowLength := -20; 
     Title:=movies[i].Title; 
     j:=0; 
     while (minDate+j<=maxDate) do 
     begin 
     if anyTicketSold(movies, minDate+j) then 
     begin 
      AddXY(minDate+j, TicketsAtDate(movies[i], minDate+j)); 

      if YValue[Count-1] = 0 then 
      SetNull(Count-1); 
     end; 

     Inc(j); 
     end; 
    end; 
    end; 
end; 
+0

感謝您的解決方案,我實際上得出了這個結論並找出了一個使用臨時表的解決方案。當我回到我的電腦時,我會發布它以獲得您的意見。 – epep

0

好了,我想出了一個辦法用臨時表中插入空值作爲隔離做;非常像Yeray的答案只是臨時表。如果有人比我有更多的知識可以比較兩者,我會很感激。因此,我首先通過Y軸上的日期和所有0值初始化X軸(僅在某些情況下避免使用0值作爲日期);然後,

With qryStatDateInitialization do 
     begin 
     SQL.Clear; 
     SQL.Add('SELECT DISTINCT ShowDate, 0 AS Blank'); 
     SQL.Add('FROM Shows'); 
     SQL.Add('WHERE MovieID IN (' + MovieIDs + ')'); 
     Open; 
     end; 

     SetLength(arrDates, 0); 

     //Populate dates array 
     qryStatDateInitialization.First; 
     SetLength(arrDates, qryStatDateInitialization.RecordCount); 
     for iCount := 0 to qryStatDateInitialization.RecordCount - 1 do 
     begin 
     arrDates[iCount] := qryStatDateInitialization.FieldByName('ShowDate').AsString; 
     qryStatDateInitialization.Next; 
     end; 

     //Series to initialize dates on X-axis 
     barSeries := TBarSeries.Create(Self); 
     barSeries.ShowInLegend := False; 
     barSeries.ParentChart := crtStatistics; 
     barSeries.DataSource := qryStatDateInitialization; 
     barSeries.YValues.ValueSource := 'Blank'; 
     barSeries.XLabelsSource := 'ShowDate'; 
     barSeries.Marks.Style := smsValue; 
     barSeries.MultiBar := mbStacked; 
     barSeries.Marks.Hide; 
     barSeries.ColorEachPoint := True; 
     barSeries.Active := True; 

接下來,我創建臨時表(每個電影),然後將0值記錄插入適當的位置。我爲此使用ID字段。

for iCount := 0 to iSelectedMovies - 1 do 
     begin 
     //Create table for movie 
     With qryEdit do 
     begin 
      //Create show table with autonumer 
      SQL.Clear; 
      SQL.Add('CREATE TABLE tempTShow'+IntToStr(iCount)); 
      SQL.Add('(ID COUNTER , Name string, ShowDate string, SeatsBooked string)'); 
      ExecSQL; 
      //Add data to show table 
      SQL.Clear; 
      SQL.Add('INSERT INTO tempTShow'+IntToStr(iCount)); 
      SQL.Add('SELECT Name, ShowDate, SeatsBooked'); 
      SQL.Add('FROM (SELECT Name, ShowDate,(SUM(NormalTickets) + SUM(ChildTickets) + SUM(SeniorTickets)) AS SeatsBooked'); 
      SQL.Add('FROM Movies, Invoice, Shows'); 
      SQL.Add('WHERE Invoice.ShowID = Shows.ShowID AND Shows.MovieID = Movies.MovieID'); 
      SQL.Add('AND Movies.MovieID = ' + DataModule1.qryStatMovieSelection.FieldByName('MovieID').AsString); 
      SQL.Add('GROUP BY Name, ShowDate'); 
      SQL.Add('ORDER BY ShowDate ASC)'); 
      ExecSQL; 
      //Set autonumber to normal integer to set show positions accordingly 
      SQL.Clear; 
      SQL.Add('ALTER TABLE tempTShow'+IntToStr(iCount)); 
      SQL.Add('ALTER COLUMN ID integer'); 
      ExecSQL; 

      Inc(iTempTableCountInternal); 
     end; 

     qryStats.SQL.Text := 'SELECT * FROM tempTShow'+IntToStr(iCount); 
     qryStats.Open; 

     //Insert 0 value spacers in temp table 
     iCountDateSort := 0; 
     iDateOn := 0; 
     While iDateOn < length(arrDates) - 1 do 
     begin 
      sDate := qryStats.FieldByName('ShowDate').AsString; 
      if NOT (sDate = arrDates[iDateOn]) then 
      With qryEdit do 
      begin 
       SQL.Clear; 
       SQL.Add('UPDATE tempTShow'+IntToStr(iCount)); 
       SQL.Add('SET ID = (ID+1) WHERE ID >= ' + IntToStr(iCountDateSort+1)); 
       ExecSQL; 

       SQL.Clear; 
       SQL.Add('INSERT INTO tempTShow'+IntToStr(iCount)); 
       SQL.Add('(ID, Name, ShowDate, SeatsBooked) VALUES (' 
       +IntToStr(iCountDateSort+1) + ',"0","0",0)'); 
       ExecSQL; 
      end 
      else 
      begin 
       qryStats.Next; 
       Inc(iCountDateSort); 
       //iDateOn := iCountDateSort; 
      end; 
      Inc(iDateOn); 
     end; 

,然後創建臨時表作爲數據源的系列,併成立0值爲null

//Create query for series 
      arrQrys[iCount] := TADOQuery.Create(Self); 
      arrQrys[iCount].Connection := conCinema; 
      arrQrys[iCount].SQL.Text := 'SELECT * FROM tempTShow'+IntToStr(iCount)+' ORDER BY ID'; 
      arrQrys[iCount].Open; 

     // create series 
     arrBarSeries[iCount] := TBarSeries.Create(Self); 
     With arrBarSeries[iCount] do 
     begin 
      ParentChart := crtStatistics; 

      YValues.ValueSource := 'SeatsBooked'; 
      arrBarSeries[iCount]. 
      XValues.DateTime := True; 
      XLabelsSource := 'ShowDate'; 
      DataSource := arrQrys[iCount]; 
      MultiBar := mbStacked; 
      Marks.Style := smsValue; 
      Marks.ArrowLength := -20; 
      Color := arrColor[iCount]; 
      Title := DataModule1.qryStatMovieSelection.FieldByName('Name') 
      .AsString; 
      Active := True; 

      for i := 0 to Count - 1 do 
      begin 
      if YValue[i-1] = 0 then 
       SetNull(i-1); 
      end; 
     end;