2010年4月28日 星期三

透過 CSS 讓列印時 Table 的標頭內容可以每頁重複

希望透過 CSS 在使用 window.print() 時,列印出來的 Table 內容(假設資料量很大),可以在每一頁都能重複標頭(Header)內容。首先,可以使用 CSS 裡的 page-break-before: always,可以強迫換頁。所以,我在範例中定義了:

<style type="text/css">
.newpage
{
page-break-before: always; 
}
</style>

假設我目前的 Table 內容如下:

<table border="1" id="tbDemo" >
  <thead>
  <tr><th id="pageHeader">編號</th></tr>
  </thead>
  
  <tbody>
  <tr><td>1</td></tr>
  <tr><td>2</td></tr>
  <tr><td>3</td></tr>
  <tr><td>4</td></tr>
  <tr><td>5</td></tr>
  <tr><td>6</td></tr>                             
  </tbody>
</table>    
接下來,使用 jQuery 讓 Table 每兩筆資料(實際上是情況而調整筆數設定)就自動產生一個標頭內容,且將這標頭內容套用剛剛加入的 CSS 設定。

<script>
$(function(){

var $rows=$("#tbDemo > tbody > tr");  
$rows.each(function(i) {
//取2的倍數,排除最後一筆
if((i+1) % 2==0 && i!=($rows.size()-1))
{
   $(this).after("<tr class='newpage'><th>"+$("#pageHeader").text()+"</th></tr>");      
}
})
})
</scrip>

如此,在使用預覽列印時,就可以看到以下每兩筆資料一頁且有標頭的結果:

原本以為,故事這樣就結束了,但...唉,看一下 FireFox 的結果~

在 FireFox (ver 3.6.3) 的標頭檔,卻重複了兩次。主要原因,是因為我的 Table 定義,用了 <thead> 與 <tbody> 的樣式。在 FireFox 裡,如果遇到換頁的時候,他會自動為每一頁的 Table 內容加上 <thead>  ,而我剛剛又手動用 jQuery 新增了一次,所以才會得到這結果。換言之,使用 FireFox 的瀏覽器,只要你的 Table 內容有用<thead> 與 <tbody> 的樣式,那每一頁自動都會幫你加上標頭喔。只是,目前我真的不希望他主動幫我加。

此時,或許加上判斷瀏覽器的程式,來決定是否要使用 jQuery 來手動增加標頭,會是一個辦法。但,我沒有這麼做。我索性就不用<thead> 與 <tbody> 的樣式。我將 Table 的定義改成以下:

<table id="tGen"  border="1" >
<tr class="trHeader"><td>編號</td></tr>
<tr class="trBody"><td>1</td></tr>
<tr class="trBody"><td>2</td></tr>
<tr class="trBody"><td>3</td></tr>
<tr class="trBody"><td>4</td></tr>
<tr class="trBody"><td>5</td></tr>
<tr class="trBody"><td>6</td></tr>
</table>

而 jQuery 也調整如下:
<script>
$(function(){
 var $rows=$("#tGen tr[class=trBody]");  
   $rows.each(function(i) {
   //取2的倍數,排除最後一筆
  if((i+1) % 2==0 && i!=($rows.size()-1))
  {     
      $(this).after("<tr class='newpage' ><td>"+$("#tGen tr[class=trHeader]").text()+"</td></tr>");
  }
   })    
});   
</script>

而最後出來的結果,就皆大歡喜了。

文章參考:
MEMO-網頁列印強迫分頁
CSS page-break-before Property
.after()
web打印中如何强制分页
Printing Tables
Printing Headers

測試程式下載:
https://sites.google.com/site/paladinsharefiles/home/filelist/RPT.zip?attredirects=0&d=1

使用 css 的 @media 控制列印樣式

想讓目前正在瀏覽的網頁直接列印出來,同時希望有些按鈕或控制項在列印時隱藏,以前我都會用 javascript 去隱藏列印時不想出現的物件。但當我看了 CSS Media Types 這篇文章後,真的就有不一樣的想法了。原來可以透過 css 裡的 media="screen" 或 media="print" 來宣告是要在螢幕上面顯示,還是只有在列印時顯示。

範例程式:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Print Friendly</title>
    <style type="text/css">
        
   .button
   {
   text-align:center;
   color:#00B3ED;
   border:1px solid #BBBBBB;
   background-color:#F0F0F0;
   line-height:12px;
   padding:4px 0px 0px;
   width: auto;
   font-size: 12px;
   }
          
    @media print 
    {
        /* 列印將物件隱藏 */
        .button { display: none; } 
    }
    </style>
    
</head>
<body>

<input type="button" id="btnPrint" value="列印" class="button" >
網頁列印
</body>
</html>

我在 style 裡面,定義了 .button  的樣式,但接著在 @media print 指定列印時,.button 的額外設定,也就是要隱藏所有有套用 .button 樣式的物件。

下圖是範例程式的執行結果,可以發現,在預覽列印時,畫面上的「列印」按鈕已經消失了。透過 CSS 來完成這功能,不管是使用瀏覽器選單選列印、預覽列印或Ctrl+P,都可以適用。



最後,附上一張沒有使用@media print 指定列印的結果,以供比較。可以看出在預覽列印時,畫面上的「列印」按鈕跑出來了。


參考文章:
活到老學到老-CSS Media Types

2010年4月23日 星期五

update from join

最近在寫一段 SQL,好不容易 join 了好幾個 table 之後,最後一個步驟就是要更新資料表。但是真的可以在 join table 裡面使用 update 嗎?還好,真的可以。


一個簡單範例:有兩個 資料表 #tmpA , #tmpB 讓他們 left join 起來

select * from #tmpA A
left join #tmpB B
on A.t_id=B.t_id
今天我希望針對 paladin 那筆紀錄,把 t_phone 欄位 用 t_name 取代。可以用以下的寫法:

update #tmpB 
--修改電話資訊
set #tmpB .t_phone=convert(nvarchar(max),A.t_name)
from  #tmpA A
left join #tmpB B
on A.t_id=B.t_id
where  A.t_id=1 --限定只改 paladin 

執行後的結果:


參考:http://www.dotblogs.com.tw/dotjum/archive/2008/06/23/4367.aspx

2010年4月21日 星期三

強迫GridView出現分頁

使用 GridView 時,如果有設定使用「分頁」功能,就會自動出現分頁效果。但你可能會發現,如果你的資料筆數少於你設定的 PageSize (預設是 10) 時,自動分頁的效果就消失了。或許這並不會有什麼影響,但如果你堅持即便是只有一筆資料,也要將分頁效果呈現的話,可以根據以下步驟來解決。

1.改寫 GridView 的 PreRender 事件
2.針對 BottomPagerRow,設定顯示狀態






protected void GridView1_PreRender(object sender, EventArgs e)
    {
        GridView gv = sender as GridView;
        if (gv != null)
        {
            GridViewRow gr = gv.BottomPagerRow;
            if (gr != null)
                gr.Visible = true;
        }

    }

參考:http://blog.sumantdubey.com/post/ASPGridView-making-Pager-always-visible.aspx

2010年4月15日 星期四

使用 Gimp 達到去背效果

 Gimp圖層遮罩的一些應用(柔化肌膚、去背(合成)、突顯主題) 學到基本的去背方式,但是還是覺得這背去的好辛苦。後來看了 三分鐘我只會這種簡單去背 ,真的就很有信心了。如果大家看了這兩篇文章,相信就有基本的去背能力了。目前我使用的 Gimp 是 2.6.7 的版本。檔案小小的,大概 17 M 左右吧。

我也搬出了正妹照,來練練功。


首先,使用工具箱的:前景選擇工具。



將所想要擷取的正妹,把它圈起來,盡量離你的正妹越近越好。圈好的圖如下:

按一下  Enter 。就會出現初步的輪廓。
















然後確定「互動式(複)製」目前是在「標記前景顏色」,並按滑鼠左鍵在正妹身上亂畫,這動作主要是讓系統自動判斷所要選取的物件確定在哪些地方。並慢慢將你所需要的物件,確定全部都有被你挑選起來。


















好不容易挑選完後,再按一次 Enter,就會出現修正後的選取區域。

















然後,我們新增一個遮罩,並指定是「選擇區域」,就可以將正妹的遮罩產生。






但還是有一些邊邊角角的地方需要修改,這時,可以用「黑色」的筆刷,去把它塗抹來修飾,最後就變得比較美一些。





接近尾聲了,再次選擇遮罩裡的:套用圖層遮罩。




為了讓這張圖有透明的背景效果,所以我把它另存為 *.png (*.gif 也可)。





我將這張圖用網頁來呈現,就可以得到一張完美的去背圖了。





更正:20120116
感謝熱心的朋友,原「互動式」名詞,因為 GIMP 工具箱的字比較小,是我看錯了。正確應該是「互動式」。可參考中文化的網站:Chinese (Hong Kong) translation of gimp,可以用搜尋「互動式精製」來找到翻譯之處,其原名是:Interactive refinement。


SQL 的 while exists

在 MS SQL 裡,盡量避免用 cursor 去處理迴圈的運算,你也許聽人說過。不管是考量效能問題也好,還是恐嚇你也好,但...下一步呢?你的問題還是需要去解決。有些人可能會提議說,那,就建立一個暫存資料表,處理過一筆資料後,就刪除他,直到這資料表沒資料為止。這真的是一個簡單好方法,可是,你有考慮過效能問題嗎?我們來做個實驗。

想要推薦的方法,是使用 while exists ( ... ) 來解決。

while exists 範例:

declare @seqsn bigint
set @seqsn=682

declare @id bigint
select  top 1 @id=gcf_id from prog_checkpoint_first 
where gcf_seqsn=@seqsn  order by gcf_id

--Do Your Job here
print @id

set @id=@id+1
while exists (select * from prog_checkpoint_first 
where gcf_seqsn=@seqsn and gcf_id>=@id)
begin

 --Do Your Job here
 select  top 1 @id=gcf_id from prog_checkpoint_first 
 where gcf_seqsn=@seqsn and gcf_id>=@id  order by gcf_id

 print @id

 set @id=@id+1

end

使用暫存資料表的方法:

declare @seqsn bigint
set @seqsn=682

declare @id bigint


select  gcf_id into #tmp from prog_checkpoint_first  
where gcf_seqsn=@seqsn  

while (select count(*) from #tmp)>0
begin
 select top 1 @id=gcf_id from #tmp 
 
 --Do Your Job here
 print @id

 delete #tmp where gcf_id = @id
end
drop table #tmp

我接著在自己的資料庫上建了一個測試資料表:prog_checkpoint_first



CREATE TABLE [dbo].[prog_checkpoint_first](
 [gcf_id] [bigint] IDENTITY(1,1) NOT NULL,
 [gcf_seqsn] [bigint] NOT NULL,
 CONSTRAINT [PK_prog_checkpoint_first] PRIMARY KEY CLUSTERED 
(
 [gcf_id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

緊接著,就是新增測試資料。我新增了2萬筆資料進去,然後分別執行「while exists 範例」與「使用暫存資料表的方法」

declare @count bigint
set @count=1

while @count<=20000
begin
 insert into prog_checkpoint_first (gcf_seqsn) values (682)
 set @count=@count+1
end

最後觀察這兩種方式的執行時間。
「while exists 範例」:2 秒
「使用暫存資料表的方法」:34秒

這結果,真的差很大。所以,當你有需要透過 SQL去處理迴圈問題,如果可預期資料量很大,那會建議使用 while exists 的寫法。如果資料量很小,則用那種都好。

2010年4月13日 星期二

關閉 window.open 視窗後,更新父視窗

在 IE 瀏覽器,如果使用 showModalDialog 對話視窗,關閉時,會自動更新原來的父視窗。但在 FF (FireFox)舊版 或 Chrome 則是因為不支援,而需改用 window.open 方式來取代。

使用 window.open 所開啟的子視窗,如果更新了某些資料,當子視窗關閉時,也希望同時去更新父視窗資料,有沒有簡單一點的方法呢?

我將需求用一張圖來表示:

在這張圖中,Parent 視窗一開始,會去抓 Session 的資料,如果 Session  有資料,則會顯示在畫面上。 我在 Parent 視窗點選編輯後,就會跳出 Son 視窗。接著就可以填入新的值來改變 Session 資料。當 Son 視窗關閉後,希望能夠去更新 Parent 視窗的資料。

為了完成這功能需求,需要以下二個步驟:

步驟一:攔截 Son 視窗關閉的事件

攔截視窗關閉的事件,可以在 Son 視窗的Html 標籤  <body>  裡,設定 onunload 屬性。

步驟二:讓 Parent 視窗觸發 PostBack

在 Son 視窗的 onunload 屬性,使用  window.opener.__doPostBack() 來觸發 Parent 視窗 PostBack

注意事項:

如果 Parent 頁面,.net 沒有幫你建立 __doPostBack javascript 的話,請記得要想方法讓他生出來,可以參考:__doPostBack 出不來?

完整測試程式參考:[ 點選 ]

PS:新版 FF、Chrome 已經支援 showModalDialog 語法。參考:FireFox showModalDialog() 

推薦 Alt + PrtScr 來擷取畫面

今天到同事位置,因為需要擷取網頁的畫面,所以自己很直覺的要使用鍵盤上的 【PrtScr】按鍵來抓圖,再用小畫家擷取想要的範圍。沒想到同事建議用 【Alt】+【PrtScr】比較快。心想,這啥麼東東啊?聽不懂。

原來,只有壓【PrtScr】按鍵,是將整個螢幕的畫面複製下來,而【Alt】+【PrtScr】,則是將目前 windows 的工作視窗(也就是你目前正使用的視窗)複製下來。

看了以下圖片,應該就瞭解了:

【PrtScr】

【Alt】+【PrtScr】



甚至連檔案總管的內容也可以抓:

的確,還真的蠻不錯用的。也不再需要安裝其他抓圖軟體,能夠抓到這種地步,應該都夠用了。

2010年4月7日 星期三

FireFox showModalDialog()

近來發現,在 FireFox 3.0 以後的版本已經開始支援 showModalDialog()的語法了。在3.0以前的 FireFox 使用,都會發生關閉後,無法更新原來頁面上資料的問題。我目前 FireFox 版本是3.6,實際測試,發現使用 showModalDialog( ) 也會有「獨占」的效果。不像以前彷彿只是用 window.open( ) 的樣式。

另外關注的一點,就是 google 自家瀏覽器 chrome。在 chrome 4.1 版,使用 showModalDialog( ) 在關閉彈跳視窗後,也能更新原來頁面,但是「獨占」效果,卻依然尚未支援。

參考:
https://developer.mozilla.org/en/DOM/window.showModalDialog
http://virendradugar.wordpress.com/2009/01/06/firefox-30-supports-showmodaldialog/

2010年4月2日 星期五

透過 jQuery 如何知道哪些元素目前是被隱藏的

透過 jQuery 將某個物件隱藏,只需下 hide() 指令即可。但如果畫面有太多物件在做類似動作,你要怎麼讓程式去知道目前哪些物件是顯示/隱藏?

舉例來說:下圖我有兩個 Div-A, Div-B 。如果我壓了 【hide A】按鈕後,Div-A 就被我隱藏了。但我希望壓下 【Show Status】按鈕後,顯示出兩個 Div 的狀態。

遇到這種狀況時,可以善用 jQuery 的 .is( ) 方法來處理。它會比對你所提供的條件,並回傳 ture 或 false。在這個範例中,就可以使用 .is(:hidden) 或 .is(:visible) 來處理。


if($("#A").is(":hidden") )
{
 .
 .
 .
}


範例程式:
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>未命名頁面</title>
    <script type="text/javascript" src="js/jquery-1.3.2.js"></script>
    <script>
        function HideA()
        {
            $("#A").hide();
        }
        
        function ShowStatus()
        {
            var vMsg='';
            if($("#A").is(":hidden") ) { vMsg+='DivA is hidden \n';} else {vMsg+='DivA is visible \n';}
            if($("#B").is(":hidden") ) { vMsg+='DivB is hidden \n';} else {vMsg+='DivB is visible \n';}
            
            $("#Msg").html(vMsg.replace(/\n/g,"<BR>"));
        }
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <div id="A" style="border-width:1; border-color:Black; background-color:Aqua; width:250px">Div-A</div>
    <div id="B" style="border-width:1; border-color:Black; background-color:Green; width:250px">Div-B</div>
    <input type="button" value="hide A" onclick="HideA();" />
    <input type="button" value="Show Status" onclick="ShowStatus();" />
    <div id="Msg"></div>
    </div>
    </form>
</body>
</html>


執行結果:


參考:http://groups.google.com/group/jquery-en/browse_thread/thread/f243d091f1b9590b?pli=1

js 取得 TextArea 的換行控制碼

可能是年紀大了,竟然為了找一個很簡單的東西,卻花了好久的時間。

我有一個 TextArea 的控制項,需要將裡面的內容存到另一個 Div 裡。如下圖所示:
可以很明顯發現,原本在 TextArea 裡有換行的內容,卻在 Div 裡全部擠在一起了。這問題的解法,就是要抓到 TextArea 的換行控制碼,並將這控制碼用 <BR> 來取代。

關鍵的指令就是: replace(/\n/g,"<br>")

/ ... / :是指正規表示式
g : 一直替換到最後

說穿了沒甚麼,但要是忘了,就要找好久。

將測試的程式整理如下:

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>未命名頁面</title>
    <script type="text/javascript" src="js/jquery-1.3.2.js"></script>
    <script>
    function ShowMsg()
    {
        var vMsg=document.getElementById("tbxInput").value;       
        $("#divContent").html($("#tbxInput").html().replace(/\n/g,"<br>"));
    }
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        TextBox:<br />
        <asp:TextBox ID="tbxInput" runat="server" Rows="5" TextMode="MultiLine" style="width:250px"></asp:TextBox>
        <input id="btnShow" type="button" value="轉入" onclick="ShowMsg();" /></div>
        <br />
        DIV:
    <div id="divContent" style="border-width:1; border-color:Black; background-color:Aqua; width:250px"></div>
    </form>
</body>
</html>

完成後的結果:

參考文章:http://www.xue163.com/html/2009121/2522346.html