2011年6月6日 星期一

Delphi ListBox 顯示多欄文字

  1. 設定 ListBox.TabWidth,單位是 Dialog Base Unit (DBU),以定寬字來說,英數字寬是 4 DBU,中文字寬是 8 DBU,所以每一欄 20 個英數字寬度的話,TabWidth 就要設定為 80
    不用管一個 DBU 合多少 Pt,DBU 是相對單位,會跟著字的大小而變化的
  2. Items.Add 時,要分欄的地方,插入 Tab 字元,可以用 #9 或是 ^I 例如:
    Items.Add('0001'#9'這是品名');
    或是
    Items.Add('0001'^I'這是品名');
  3. 沒辦法各欄設定不同寬度,所以 TabWidth 請設定大一點,或是最長的欄放最後
    如果一定要各欄不同寬度顯示,請改用 TListView

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; image

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日 星期三

Ultra VNC 的最佳選項

1. 要搭配 Video Hook Driver
2. 「Check the Cideo Hook Driver」按鈕要連線時按才有意義image

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()

這種方法的缺點是
  1. 如果在這個TemplateField 之前,加入或是刪掉了其他欄,或是修改了 TemplateField 的 ItemTemplate,事件處理都得修改
  2. 如果不是以 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" ? "否" : "");
}
這樣的好處是

  1. 不用數格子
  2. 沒有複雜的資料繫結語法
  3. 無論從何種資料來源做資料繫結,都可以適用
  4. 可檢查資料是否為 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;