- 設定 ListBox.TabWidth,單位是 Dialog Base Unit (DBU),以定寬字來說,英數字寬是 4 DBU,中文字寬是 8 DBU,所以每一欄 20 個英數字寬度的話,TabWidth 就要設定為 80
不用管一個 DBU 合多少 Pt,DBU 是相對單位,會跟著字的大小而變化的
- Items.Add 時,要分欄的地方,插入 Tab 字元,可以用 #9 或是 ^I 例如:
Items.Add('0001'#9'這是品名'); 或是 Items.Add('0001'^I'這是品名');
- 沒辦法各欄設定不同寬度,所以 TabWidth 請設定大一點,或是最長的欄放最後
如果一定要各欄不同寬度顯示,請改用 TListView
2011年6月6日 星期一
Delphi ListBox 顯示多欄文字
2011年6月2日 星期四
Delphi + PostgreSQL 處理 bytea 欄位的注意事項
設定 PostgreSQL ODBC 時,要把圖中的「bytea as LO」選項勾起來,這樣使用 bytea 欄位型態就會被判別成 TBlobField,而不是 TVarBytesField
如此一來,就可以使用 TBlobField.LoadFromFile() 跟 SaveToFile() 來存入與讀取 bytea 欄位的內容了
若讀取時只想使用 TImage 顯示,不想存檔也可以 (以 JPG 圖檔為例子)
uses jpeg; // 支援 JPEG 圖檔
var blob: TStream;
blob := ADODataSet1.CreateBlobStream(BlobField, bmRead);
try
blob.Seek(0, soFromBeginning);
Image1.Picture.Graphic := TJPEGImage.Create;
Image1.Picture.Graphic.LoadFromStream(blob);
finally
blob.Free
end;
2011年5月12日 星期四
XMLHttpRequest 的應用:灌垃圾資料給釣魚網站
今天有一個許久未聯絡的同學忽然間丟 MSN 水球給我,第一時間的直覺就是詐騙,要買遊戲儲值卡的。果不其然,聊不到兩句就開始問我有沒有空,可不可以幫他買卡等等,我用幾個爛藉口推掉之後,他留下一個超連結就離線了。
點擊超連結,果然出現一個很像 Windows Live 登入的網頁,做得十分粗糙,連 Title 都沒有改,還是 “Untitled Document”,唉~~要騙人帳號也搞像一點嘛!於是我就拿出了我之前寫的小程式,一個 html 檔案,填入了一些資料,開始向那個釣魚網站灌垃圾資料。
這隻程式很簡單,就是使用 XMLHttpRequest 對釣魚網站 POST 假資料,假資料當然是使用亂數產生,主要的部份是這樣子的:
// 產生一個 XMLHttpRequest 物件
function initRequest()
{
var A = null;
try
{
A = new ActiveXObject("Msxml2.XMLHTTP")
}
catch(e)
{
try
{
A = new ActiveXObject("Microsoft.XMLHTTP")
}
catch(oc)
{
A = null
}
}
if (!A && typeof XMLHttpRequest != "undefined")
{
A = new XMLHttpRequest()
}
if (!A && window.createRequest)
{
try
{
A = window.createRequest();
}
catch (e)
{
A = null;
}
}
return A
}
// 取亂數帳號密碼,塞入釣魚網頁
function DoBurst()
{
try
{
// 宣告變數
username = "";
password = "";
// 取得輸入資料
actionUrl = document.getElementById("actionUrl").value;
usernameId = document.getElementById("usernameId").value;
passwordId = document.getElementById("passwordId").value;
// 取亂數拼湊假的帳號跟密碼
c = Math.floor(Math.random() * 8) + 5;
for (n=0; n < c; n++)
{
username += charSet.charAt(Math.floor(Math.random() * charSet.length));
}
username += document.getElementById("usernameSuffix").value;
c = Math.floor(Math.random() * 8) + 5;
for (n=0; n < c; n++)
{
password += charSet.charAt(Math.floor(Math.random() * charSet.length));
}
// submit
url = actionUrl + "?" + usernameId + "=" + username + "&" + passwordId + "=" + password;
if (typeof XmlHttp == "undefined")
{
XmlHttp = initRequest();
}
XmlHttp.open("POST", url, true);
XmlHttp.onreadystatechange = ShowResult;
XmlHttp.send("");
// 計數器累加,並更新畫面
i++;
document.getElementById("sendTimes").innerText = i;
}
catch(e)
{
// 可做錯誤處理
}
}
然後使用 interval 定時重複執行,就這樣簡單!
2011年3月9日 星期三
2011年1月30日 星期日
Ubuntu Server 10.10 安裝 ASP.Net 網站伺服器的步驟
一、安裝 mono 以及 xsp
sudo apt-get install mono-gmcs
sudo apt-get install mono-xsp2
sudo apt-get install mono-apache-server2
sudo apt-get install libapache2-mod-mono
sudo a2enmod mod_mono
二、修改 /etc/apache2/mods-enabled/mod_mono.conf
成為以下這樣:
===== 從這裡開始 =====
AddType application/x-asp-net .aspx .ashx .asmx .ascx .asax .config .axd
DirectoryIndex index.aspx
DirectoryIndex Default.aspx
DirectoryIndex default.aspx
MonoAutoApplication enabled
MonoServerPath "/usr/bin/mod-mono-server2"
Include /etc/mono-server2/mono-server2-hosts.conf
===== 到這裡結束 =====
三、重新啟動 apache2
sudo /etc/init.d/apache2 restart
若要讓 Visual Studio 跟 MonoDevelop 共用網站專案的話
要使用「ASP.Net 應用程式」開發,不可以使用「ASP.Net 網站」開發
這樣平常就可以使用 Visual Studio 開發,要部署到 Ubuntu Server 時,再用 MonoDevelop 編譯一次就好
2010年11月7日 星期日
ASP.Net GridView 的自訂資料繫結
在論壇上,常常看到有網友提出這樣的問題:如果資料值是 Y/N,要顯示 是/否 在 GridView 上,要如何做?
這個問題有幾種解法
第一種:使用 GridView.RowDataBound 事件,搭配 TemplateField
這種方法是大部分的書上會介紹的方法
RowDataBound 事件,會傳入一個型別為 GridViewRowEventArgs 的參數 e
e.Row 指的是 GridView 剛剛做完資料繫結的列
e.Row.DataItem 指的是用來做這個列的資料繫結的資料來源,型別是 object
如果以 DataTable 或是 DataSet 做資料來源,e.Row.DataItem 實際上是一個 DataRowView
所以,如果以 DataTable 或是 DataSet 做資料來源,(e.Row.DataItem as DataRowView).Row["欄位名稱"] 可以取得欄位的資料值
接下來,就是「數格子」,要知道你的 TemplateField 是第幾欄,還要知道要做自訂資料繫結的控制項是 ItemTemplate 的第幾個控制項
(e.Row.Cells[欄索引].Controls[控制項索引] as 控制項型別).Text =
(e.Row.DataItem as DataRowView).Row["欄位名稱"].ToString()
或是要知道自訂資料繫結的控制項的 ID
(e.Row.Cells[欄索引].FindControl("控制項ID") as 控制項型別).Text =
(e.Row.DataItem as DataRowView).Row["欄位名稱"].ToString()
這種方法的缺點是
- 如果在這個TemplateField 之前,加入或是刪掉了其他欄,或是修改了 TemplateField 的 ItemTemplate,事件處理都得修改
- 如果不是以 DataTable 或是 DataSet 做資料來源,e.Row.DataItem 事實上是什麼型別?
不確定因素太多,既麻煩又複雜!強烈不建議使用這個方法
第二種:使用單純自訂資料繫結,搭配 TemplateField
這種方法直接在 TemplateField 的 ItemTemplate 中放置一個 Label,並設置 Text 屬性的資料繫結為 Text='<%# Eval("欄位名稱").ToString() == "Y" ? "是" : (Eval("欄位名稱").ToString() == "N" ? "否" : "") %>' Text='<%# Eval("欄位名稱", "{0}") == "Y" ? "是" : (Eval("欄位名稱", "{0}") == "N" ? "否" : "") %>'
簡單明瞭,只是判斷是寫在 .aspx 裡面,而且當資料值是 DbNull 的時候會發生錯誤,如果還要加上判斷是否為 DbNull 的語法就更複雜了
因此,此方法建議使用於簡單判斷以及資料欄位不允許 null 的狀況
PS: Eval("欄位名稱") 與 Eval("欄位名稱", "{0}") 的不同點在於前者回傳的是 Object,後者回傳的是 String
第三種:使用自訂資料繫結方法,搭配 TemplateField
跟第二種方法類似,只是將 Label 的 Text 屬性的資料繫結改為呼叫一個自訂方法 (必須為 public 或 protected 方法)
Text='<%# YesOrNo(Eval("欄位名稱")) %>'
並撰寫後端程式碼如下:
protected string YesOrNo(object o)
{
string s = o == DbNull.Value ? "" : Convert.ToString(o);
return s == "Y" ? "是" : (s == "N" ? "否" : "");
}
這樣的好處是
- 不用數格子
- 沒有複雜的資料繫結語法
- 無論從何種資料來源做資料繫結,都可以適用
- 可檢查資料是否為 DbNull
2010年11月3日 星期三
Delphi 5 使 DBGrid 支援滑鼠滾輪的程式碼
Delphi 5 的 TDBGrid 無法支援滑鼠滾輪移動資掉指標,而且當有 PickList 的 Column 或是 Lookup Field 下拉時
滾動滑鼠滾輪會有很奇怪的行為。
要解決這個問題,可以繼承 TDBGrid 寫一個新的 DBGrid 類別,並覆寫兩個方法:
interface type TNewDBGrid = class(TDBGrid) protected function DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): Boolean; override; function DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): Boolean; override; end; implementation function TNewDBGrid.DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): Boolean; begin Result := False; if Assigned(OnMouseWheelDown) then OnMouseWheelDown(Self, Shift, MousePos, Result); if (not Result) and (DataLink <> nil) and (DataLink.Active) and (DataLink.DataSet <> nil) and (DataLink.DataSet.Active) then begin DataLink.DataSet.MoveBy(1); Result := True; end; end; function TNewDBGrid.DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): Boolean; begin Result := False; if Assigned(OnMouseWheelDown) then OnMouseWheelDown(Self, Shift, MousePos, Result); if (not Result) and (DataLink <> nil) and (DataLink.Active) and (DataLink.DataSet <> nil) and (DataLink.DataSet.Active) then begin DataLink.DataSet.MoveBy(-1); Result := True; end; end;