总打印页数及 手工 画线等几个 打印问题,100分奉送,欢迎阅读:(100分)

  • 主题发起人 主题发起人 mjwmjw
  • 开始时间 开始时间
M

mjwmjw

Unregistered / Unconfirmed
GUEST, unregistred user!
1。如何在PAGEFOOTER 实现显示打印的 总页数?
2。参阅下面的程序,我想在 打印预缆和打印时画一些线和输出一些字符(主要是想在
DATADETAIL区右边留下一个窄的矩形,可以在上面任意的画一些表格或一些字符,不知道
用控件怎么做,只好想直接画---当然如果能留下一个举行区域,那就更好了),尝试如下
,结果程序在此处不能 运行,
procedure TprintMx.QuickRep1BeforePrint(Sender: TCustomQuickRep;
var PrintReport: Boolean);
begin

with QuickRep1.QRPrinter do

begin

begin
doc;
Canvas.textout(100,100,'laksdjiouojlkajdslkuiojlkajsdoiuk');
enddoc;
end;

end;

3,在打印同一个表单时,第一页的PAGEFOOTER和剩下页的PAGEFOOTER不一样,我如何
能在第一页打印完时,更改QRREPORT的 PAGEFOOTER,是否需要再做一个FORM,在上面
重绘 表格,在第一页打印完时更换 第二个FORM?
 
下面这些代码应该可以解决三个问题——

var
bFirst: Boolean;//是否为第一页的标志
nPageCount: Integer;//总页数

procedure TForm1.Button1Click(Sender: TObject);
begin

QuickRep1.Prepare;//预览或打印前先执行这一句
nPageCount := QuickRep1.QRPrinter.PageCount;//以便获得总页数
QuickRep1.Preview;
end;


QuickRep的BeforePint事件——
procedure TForm1.QuickRep1BeforePrint(Sender: TCustomQuickRep;
var PrintReport: Boolean);
begin

bFirst := True;//每次预览之前将它置为True
end;


比如在PageFooter里放一个TQRLabel;
那么在QuickRep的OnStartPage事件里——
procedure TForm1.QuickRep1StartPage(Sender: TCustomQuickRep);
begin

if bFirst then
begin

bFirst := False;//如果是第一页,则清掉标志
QRLabel1.Caption := 'This is the first page.';//并且显示这个字符串
end else
QRLabel1.Caption := IntToStr(nPageCount);//否则显示总页数
end;


在DetailBand的(100,100)座标位置放一个TQRImage,大小根据实际需要调整;
在DetailBand的的AfterPrint事件里——
procedure TForm1.DetailBand1AfterPrint(Sender: TQRCustomBand;
BandPrinted: Boolean);
begin

QRImage1.Canvas.TextOut(0, 0, 'laksdjiouojlkajdslkuiojlkajsdoiuk');
end;
 
thanks dq:
i still some question about the three quetion,
1.第一个答案可行,但运行后,预缆速度明显变慢。简直不可忍受,如果记录多那可怎么办?

2.我所说的DATADETAIL右边留下 一块区域,是指整个页面而言,而不是指 单一记录的右边
所以,TEXTOUT 输出的坐标也应该是 相对于整个 页面。

3.我所说的PAGEFOOTER的不同,不仅仅是一个LABEL的问题,高度不一样,表格的多少也不
一样。所以可能还得 有进一步的解决措施,
4,对于整个问题的解决,如果在整个页面的右边能留下一个矩形(也象一个BAND,只不过
是靠右边而已),那么整个问题就能解决了。
仍然希望大家能给予帮助,谢谢!
 
>>4,对于整个问题的解决,如果在整个页面的右边能留下一个矩形(也象一个BAND,只不过
>>是靠右边而已),那么整个问题就能解决了。
在BeforePrint事件中:
with TQRShape.Create(self)do

begin

Parent := QuickReport;
Top := DetailBand.Top;
Left := DetailBand.Left + 表格的宽度;
Width := DetailBand.Width - 表格的宽度;
Height := 表格的高度;
end;

同样,也可以在报表页面的某个位置打印一条信息。

 
1.确实会有这个问题,但是为了得到总页数不得不先Prepare,帮助里也是这么做的;
不知道还有没有其它的得到总页数的方法。所以现在只能给你两点建议——
把QuickRep.Options属性里的Compression置为True;
预览的时候调用QuickRep.PreviewModeless。——不过都不敢保证效果:)

2.可以在QuickRep的OnEndPage事件里通过QuickRep.Canvas绘制,因为这时候就不会被
其它控件的绘制所覆盖了。在BeforePrint事件里对Canvas进行操作的确会报错的。

3.试试在PageFooterBand的BeforePrint事件里结合QuickRep.QRPrinter.PageNumber,
并根据表格的大小和布局动态调整PageFooterBand的外观以及其中的信息。
不过你没有说得很清楚,不知道到底要对PageFooterBand做什么样的调整。

4.“在整个页面的右边能留下一个矩形”,就是根据实际情况做相应计算的问题。
 
非常谢谢 DQ 和LIULY 二位的大力支持。
还有一点不明白的地方 继续请教DQ:

2, QuickRep 里没有Canvas,而QuickRep.QRPRINTER有 CANVAS,实现了你说的TEXTOUT,
这里有一个问题是:坐标定位 很困难(参看其中控件的LEFT,TOP,等属性,他们
都没用与QRPRINTER。CANVAS的坐标好象没有任何关联),即使这样,我不断的一点一点的
试,也找准了位置,但,打印的时候是否会发生 “变形”,不同的打印机是否有一样的效果?
难道他们的坐标之间真的没有一点联系?
另外:要实现这种TEXTOUT等,是否可以不在QuickRep的OnEndPage事件里?其余的什么
事件还可以做这样的事情。
3,>>不过你没有说得很清楚,不知道到底要对PageFooterBand做什么样的调整。
PAGEFOOTER的不同主要是 第一页 的PAGEFOOTER 多了几个水平方向的表格,占的高度
也相应的大一些,另外他们的表格结构也不完全一样。
4,>>BandTy p e 属性的取值
>>r b O v e r l a y :一个覆盖边条,从一页的左上角开始打印,而且覆盖该页中的其他>>
>>边条
这个BAND你用过吗?能否产生 任意 矩形的效果?


 
2.>>QuickRep 里没有Canvas
呵呵,是我疏忽了:)

在使用控件的Left、Top等属性时,一定要注意控件的层次——
只有QuickRep控件的直接下级控件,即Parent属性为QuickRep的控件,
其座标和QuickRep.QRPrinter.Canvas里的座标才是一致的;
如各个QRBand、直接放在QuickRep上的TQRLabel等。
其它放在Band里的控件的座标是相对于各个Band的。
——这一点和Form上普通控件的层次关系是一样的。

另一点要特别注意的是在运行期引用的QRBand.Top等属性还是设计期的!
比如不能认为PageFooterBand.Top就是实际预览时PageFooterBand在QuickRep上的绝对位置。

我认为对于“在整个页面的右边留下一个矩形”这个问题,其难点就是怎样准确地定位
PageFooterBand.Top相对于整个页面的实际值。结合上述需要注意的两点,可以这样解决——

在QuickRep所在Form的OnCreate事件里写这么两句:

QuickRep1.Page.Units := Pixels;
PageBottom := QuickRep1.Height - Round(QuickRep1.Page.BottomMargin);
//PageBottom是一个Integer型的全局变量。

这样就得到了以像素为单位的可打印页面的纵向范围,这是关键所在!
然后,在QuickRep上放一个QRImage,注意一定要“直接”放在QuickRep上!
在QuickRep.OnEndPage事件里就可以动态地调整每一页的矩形高度了——

QRImage1.Top := DetailBand1.Top;
if QuickRep1.QRPrinter.PageNumber > 1 then
//如果不是第一页
QRImage1.Top := QRImage1.Top - TitleBand1.Height;//则TitleBand不可见,于是DetailBand向上移动了
QRImage1.Height := PageBottom - PageFooterBand1.Height - QRImage1.Top;

接着就可以在该QRImage的Canvas上绘制需要的东东了(至于PageFooterBand1.Height的确定,稍后再说)。

——建议最好还是对QRImage.Canvas进行操作,而不要针对QuickRep.QRPrinter.Canvas,
不然的话虽然预览可以,但打印的时候确实很可能出问题。
——把打印工作交给QReport控件自己去处理毕竟是最保险的方式:)
并且这样的话,矩形区里的座标引用就可以直接相对于该矩形(QRImage)了,比较方便。


>>要实现这种TEXTOUT等,是否可以不在QuickRep的OnEndPage事件里?

之所以利用这些事件,是因为它们可以提供适当的时机,具体选择哪个事件要看实际的需要。
从上述的方法来说,我建议用PageFooterBand的AfterPrint事件,这样逻辑上可能更清楚一些;
因为我们需要得到PageFooterBand.Height之后再决定QRImage.Height。

3.关键是看你能不能掌握表格的高度信息,如果可以,那就很简单了。
在PageFooterBand的BeforePrint事件里进行判断——

if QuickRep1.QRPrinter.PageNumber = 1 then
begin

......
PageFooterBand1.Height := ...
......
end else
begin

......
PageFooterBand1.Height := ...
......
end;


4.帮助里对rbOverlay的解释是——

Included for backwards compatibility with QuickReport version 1.do
not use this band type
~~~~~~~~~~~~~~~~~~~~~~~~~

——所以我没有用过。并且对于“产生 任意 矩形的效果”表示怀疑:)
 
非常感谢 DQ ,我现在感觉 100 分实在是有一点少了,先记在帐上罢。
同时,还得再麻烦你:
2,>> 接着就可以在该QRImage的Canvas上绘制需要的东东了(至于PageFooterBand1
我用QRIMAGE成功实现,谢谢,因为我的表的特殊性,QRIMAGE 不用动态创建,我用QRIMAGE
覆盖了整个DATADETAIL和PAGEFOOTER区的右边的一部分,形成了一个矩形区,这样就可以任
我操作了
>>在使用控件的Left、Top等属性时,一定要注意控件的层次
----QuickRep1的坐标单位,我的是MM(bottomMargin等都是用这个单位),但
QuickRep.left是 -3 ,top = -5,这个值应是相对与PAGE的,但他的 ‘单位’又是什么?
如果是 mm 的话,left 与 leftmargin(=10) 有什么关系?直接对QRPrinter.Canvas里画
线和 textout时,好象用的坐标 是象素?为什么?
这些单位的变化(尤其是 象素)是否会 因不同的 打印机而有不同的效果?参看下面语句:
PointX,pointY:integer;
pointX:= GetDeviceCaps(printer.handle,LOGPIXELSX);
pointY:= GetDeviceCaps(printer.handle,LOGPIXELSY);
printer.canvas.rectangle(0,0,pointX*1,pointY*2);
以上语句好象是考虑打印机的分辨率的因素,什么情况下用合适?
3,>>关键是看你能不能掌握表格的高度信息,如果可以,那就很简单了
关于PageFooterBand的“高度”问题,我想我能尝试 把握住,但里面有不少表格,是不是从
第二页开始 全部都要 动态创建?并且把第一页的PageFooterBand里的内容全部不可视?
---能不能做两个FORM,第一页打印完之后 进行切换?(只是一个构思)
5,我用了QRsysdata的qrsdetailNo.(用来对记录记数),我能不能 让qrsdetailNo在每一
页开始时候都重新开始记数?
先谢谢了!
 
2. >>QuickRep.left是 -3 ,top = -5,这个值应是相对与PAGE的,但他的 ‘单位’又是什么?
QuickRep本身的位置座标不是相对于Page的,是相对于Form的,和其它控件(如Button、Panel)是一样的;单位是像素。

>>left 与 leftmargin(=10) 有什么关系?
你是说QuickRep.Left和QuickRep.Page.LeftMargin吧,它们的概念是不同的——
QuickRep.Left的含义如上,它与预览或打印无关;
QuickRep.Page.xxxxMargin等四个属性是纸张上下左右的边距。
也就是在设计期可以看到的QuickRep控件上兰色虚线框和QuickRep控件边界之间的部分。
——所以对于预览和打印来说,它们两个没有什么关系。

至于单位问题,帮助里对QuickRep.Units的解释是:

QuickReport allows you to work with several different units of measurement while designing reports.
~~~~~~~~~~~~~~~~~~~~~~~
The Units property is used to select what unit type you want to work with.
~~~~~~~~~

也就是说这个值(MM、Pixels等)主要是为了设计时的方便直观而用的;
当然,帮助里还有这么一句:

QuickReport will automatically convert all values throughout the report to reflect the newly selected unit.
~~~~~~~~~~~~~~~~~~~~~
所以可以利用它很简单地实现像素和毫米数值之间的转换等工作,就象我用到的——

>>QuickRep1.Page.Units := Pixels;//由默认的毫米转换为像素
>>PageBottom := QuickRep1.Height - Round(QuickRep1.Page.BottomMargin);//得到以像素为单位的值

要注意的一点是在生成报表的过程中,不管Units属性设为何值,LeftMargin的值是不变的!
这一点和“另一点要特别注意的是在运行期引用的QRBand.Top等属性还是设计期的!”是类似的;
但不同的是——
比如你用A4规格的纸张,Units为MM的话,在设计期可以看到LeftMargin=10.0mm;
但是在报表生成过程中得到的LeftMargin的值却是100.00!
再次强调:无论Units属性设为何值,都是这个数!
——说明这时的单位是0.1mm?(拿不准,没有查到相关的资料)
不过只要不在报表生成过程中引用LeftMargin就没问题了。

>>直接对QRPrinter.Canvas里画线和 textout时,好象用的坐标 是象素?为什么?

呵呵,不为什么,就是这么规定的;TCanvas也是这样嘛,你只要知道按像素单位给座标就行了:)

>>这些单位的变化(尤其是 象素)是否会 因不同的 打印机而有不同的效果?

我想这个问题在上面已经解释清楚了:单位的变化对同一张报表的打印效果没有影响。
在不同的打印机上看到的效果以及打印和预览时看到的效果的差异应该是
打印机之间以及打印机和显示器之间的分辨率的不同造成的。

至于GetDeviceCaps函数,你给出的两句确实是获取打印机的水平和垂直分辨率用的。
但我没有实际地用过——所以我说不准“什么情况下用合适”:)

3. 这个问题可以尝试这样解决——

给PageFooterBand加两个ChildBand(TQRChildBand);
比如在QRChildBand1里显示第一页需要的表格,在QRChildBand2里显示另一个表格;
把PageFooterBand.Height设成0;
然后在PageFooterBand的BeforePrint或者AfterPrint事件里写——

QRChildBand1.Enabled := QuickRep1.QRPrinter.PageNumber = 1;
QRChildBand2.Enabled := not QRChildBand1.Enabled;

5. 我认为答案应该是不能。不过这个问题不难解决——

用一个TQRLabel代替TQRSysData;
声明一个全局变量 nDetailNo: Integer;
在QuickRep的OnStartPage事件里加上这么一句:
nDetailNo := 1;//换页的时候重置为1

在TQRLabel的OnPrint事件里写——
procedure TForm1.QRLabel1Print(sender: TObject;
var Value: String);
begin

Value := IntToStr(nDetailNo);//显示按页排的行号
Inc(nDetailNo);//逐行递增
end;
 
to dq:
根据你的建议,问题基本已全部解决尤其是关于 3 的建议很好:
>>给PageFooterBand加两个ChildBand(TQRChildBand);
用起来很方便, 但完全按你的建议做后,还有一点小问题,还得再请教你一下:
A。QRChildBand1 比QRChildBand2的表高度要大一些,显示完全正常,在
第二页显示时,由于 QRChildBand2 表格高度小一些,应该可以多打印几条记录,但现在打印
的记录数目却不变,而QRChildBand2却向上靠(应向底靠的),结果底部留下了一片空白。
B。同时第三页(也是最后一页) 没有 QRChildBand 打印,整个一片空白。我修改LastPagefooter也没用。
---我试着动态修改QRChildBand2的top属性(在QRChildBand2.onbeforprint),不起作用,我
觉得应在 新的一页 开始打印时,或当QRdatadetail 打印 检测可用 空间时,这个 top 信息就
应该传递到位(或者用其他的方法)。不知道 每页打印多少记录是什么时候确定的?同时为什么最后一页没有QRChildBand打印?
6,最后一个问题:想让记录隔行打印(之间留一空行),同时空行也一起参与排记录号(即1,2,3,4
5....持续到本页结束),怎样做好?
 
A、B(这两个应该是同一个原因造成的问题):
确实比较邪门!并且在我这儿试了一下,现象跟你的还不太一样,但也是有问题的:(
——我说不清原因在哪儿(估计和ChildBand本身的性质以及QRBand之间的父子关系规则有关);
但调整Top属性应该是没用的,在设计期也是不能改的;
所以只好不断的地试验,最后我发现这样可以解决(但不敢保证在你那里行不行的通)——

在动态调整两个ChildBand的Enabled属性的同时,调整它们的ParentBand,即加上下面的语句:

if not QRChildBand1.Enabled then
QRChildBand1.ParentBand := nil
else
QRChildBand1.ParentBand := PageFooterBand1;

if not QRChildBand2.Enabled then
QRChildBand2.ParentBand := nil
else
QRChildBand2.ParentBand := PageFooterBand1;

6.呵呵,这个不难吧,稍微变通一下嘛——
给DetailBand也加一个ChildBand,高度和DetailBand一样;
在里面也放一个TQRLabel,外观和DetailBand里那个显示行号的QRLabel一样;
在这个QRLabel的OnPrint里写上同样的代码,就OK了!
 
to dq:
还得再和你讨论一下 问题3:
3。首先我按照你的方法试了一下,不行。我不知你利用这个方法可以实现到怎样的程度。
我还尝试将 QRChildBand2的parentband 改为QRChildBand1 ,先将QRChildBand2.height设为0。在pageheaderAfterPrint
的事件中做一下事情:
if QuickRep1.QRPrinter.PageNumber <> 1 then

begin

QRChildBand2.height:=120
QRChildBand1.height:=0;
end;

//依然没用,
如果先将QRChildBand1与QRChildBand2 的高度都设计为0,在动态中修改,结果在打印时候,记录竟然一直打印到页面底部,
QRChildBand在页面外打印, 是否说明每页打印的记录数只与设计时的状态有关?
唉,我实在是没办法了。 而且最后一页还是没有PAGEFOOTER 打印?功亏一篑。实在不行,可能只好换
控件了, 有人说 EHLIB 不错,不知怎样,仍想听你的高见! 无论如何还是太谢谢你了!
 
唉,确实是问题越来越多了!
如果动态设Parent属性,到后来竟然会出现API调用失败这个最不想见到的错误!
我当时试的时候两个ChildBand的高度都不大,所以没看出来它们没打到底。
这个按理说应该可以解决,可以用QuickRep的ResetPageFooterSize方法进行调整,
不管是改Enabled属性还是Height,效果应该是一样的(还是别用Parent了,不标准),
就是在调整过以后加一句:QuickRep1.ResetPageFooterSize;
并且最好在报表生成过程中只调整两次(否则问题更多),即第一页和第二页各一次。
这样的话ChildBand向底靠的问题是可以解决,但是更奇妙的事情发生了:
就是你说的第三页没有Footer,事实上,除了第一页以后的所有奇数页都是这样!
你可以多弄一些数据(或者加高DetailBand)让它多打几页看看是不是这样,
如果你那边也是这样,恐怕就真得换控件了:( ——唉,惭愧!

——或许咱们的思路都已经有些局限于此了,再看看大家还有什么好办法吧。

EHLIB我没有用过(事实上我也没有见过,别笑我哦:),我没有发言权。
 
整个问题非常感谢 dq ,liuly的回答。
不过问题还不算彻底结束,热心者仍可以继续发表见解,我可以在其他地方给分。
 
后退
顶部