搜尋此網誌

2009年12月29日 星期二

Silverlight:Web Load Media

建立一個Button物件,按下後能動態載入影片檔案。這樣的動作可以運用於「需要時才載入」,避免Silverlight的xap檔案過大導致載入時間過長。

在撰寫程式之前,請先新增一個新的專案到目前的solution中,並且將影象檔案置入該新增的專案:

新增專案至Solution,本篇將新增的專案命名為「VedioPack」

將影片檔加入專案中,在此以「_Butterfly_Small.wmv」為例:


在 .xmal檔中加入以下程式碼:

<Grid x:Name="LayoutRoot">
 <Button Width="100" Height="30" Content="load vedio" VerticalAlignment="Top"
Click="loadVedio" />
  <MediaElement Height="180" VerticalAlignment="Center" Width="240"
   d:LayoutOverrides="Width" HorizontalAlignment="Stretch"
   Volume="1" x:Name="vedio" Stretch="Uniform"/>
 <TextBlock x:Name="progressText" Text="%" Margin="-100,0"
  HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>


上述程式碼中,TextBlock元件將會顯示目前Media檔案的下載進度。接著在 .cs 檔案加入以下程式內容:

當按鈕被Click時:

private void loadVedio(object sender, RoutedEventArgs e)
{
  WebClient wc = new WebClient();
  wc.DownloadProgressChanged +=
  new DownloadProgressChangedEventHandler(wc_DownloadProgressChanged);
  wc.OpenReadCompleted +=
  new OpenReadCompletedEventHandler(wc_OpenReadCompleted);
  wc.OpenReadAsync(new Uri("ClientBin/VedioPack.xap", UriKind.Relative));
}

下載中,檔案下載進度的反應:

void wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
  progressText.Text = e.ProgressPercentage.ToString() + "%";
}

下載檔案的結果:

void wc_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
  if ((e.Error == null) && (e.Cancelled == false))
  {
   try
   {
    StreamResourceInfo sri =
      new StreamResourceInfo(e.Result as Stream, null);
    Uri uri =
      new Uri("_Butterfly_Small.wmv", UriKind.Relative);
    StreamResourceInfo mediaStream = Application.GetResourceStream(sri, uri);
    this.vedio.SetSource(mediaStream.Stream);
    progressText.Visibility = Visibility.Collapsed;
   }
   catch(Exception ex)
   {
    System.Windows.Browser.HtmlPage.Window.Alert(ex.Message);
   }
  }
  else
  {
   MessageBox.Show(e.Error.ToString());
  }
}


執行結果

2009年12月28日 星期一

Silverlight:下載進度

1、先在 .xaml 檔內的UserControl加入以下程式碼:

<Grid x:Name="LayoutRoot" Height="100" Width="300" Loaded="downloadObj">
 <Rectangle Fill="Black" />
 <Rectangle x:Name="bg"  Fill="Red" Height="20" Width="200"
  HorizontalAlignment="Left" Margin="50,0"/>
 <Rectangle x:Name="bar" Fill="Yellow" Height="20" Width="1"
  HorizontalAlignment="Left" Margin="50,0"/>
 <TextBlock x:Name="progressText" Text="0%" FontSize="15"
  Foreground="White" HorizontalAlignment="Center"
  VerticalAlignment="Center"/>
</Grid>


2、接著生出一個檔案,將檔案放到專案的「ClientBin/」之下(與xap檔案同資料夾,在此以SilverlightVideoPlayerClassLibrary.zip為例)
3、在.cs檔寫入以下程式碼:

private void downloadObj(object sender, RoutedEventArgs e)
{
 WebClient wc = new WebClient();
 wc.DownloadProgressChanged +=
   new DownloadProgressChangedEventHandler(wc_DownloadProgressChanged);
 wc.OpenReadCompleted += new OpenReadCompletedEventHandler(wc_OpenReadCompleted);
 wc.OpenReadAsync(new Uri("SilverlightVideoPlayerClassLibrary.zip",
           UriKind.Relative));
}

void wc_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
 if (e.Error == null)
 {

 }
 else
 {
  MessageBox.Show("error : " + e.Error.ToString());
 }
}

void wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
 bar.Width = (double) e.ProgressPercentage * 2;
 progressText.Text = e.ProgressPercentage.ToString() + "%";
}


progressText為TextBlock元件,在此利用WebClient做到檔案下載的動作,以event handler取得下載進度,反應於 wc_DownloadProgresshanged中。

2009年12月23日 星期三

Silverlight:物件化管理----Add Reference

1、建立新的Sliverlight專案:


2、在相同的solution下,額外新增一個專案(Silverlight Class Library):


3、Project add reference,對主專案按下滑鼠右鍵,選擇「Add reference」,reference的對象則是先前新增的Project:

在主要專案找到「Reference」,會看見額外新增的專案已被加入


4、在額外新增的專案中加入xmal檔,並建立內容:


選擇「Silverlight User Control」並指定xmal檔名


新增的專案中,其新增的xmal檔內容如下

<UserControl x:Class="LoadedXAML.execAnimation"
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 Width="400" Height="300">
  <Grid x:Name="LayoutRoot" Loaded="whenLoaded">
   <Grid.Resources>
    <Storyboard x:Name="anima">
     <DoubleAnimation Storyboard.TargetName="path1"
       Storyboard.TargetProperty=
       "(Rectangle.RenderTransform).X"
       From="0" To="300" AutoReverse="true"
       BeginTime="0:0:0"
       Duration="0:0:2" RepeatBehavior="Forever"/>
    </Storyboard>
   </Grid.Resources>
  <Grid>
   <Rectangle x:Name="path1" Opacity=".65" Fill="orange"
    Height="100" Width="100" RadiusX="10" RadiusY="10" >
    <Rectangle.RenderTransform>
     <TranslateTransform X="0"/>
    </Rectangle.RenderTransform>
   </Rectangle>
  </Grid>
 </Grid>
</UserControl>

新增的xmal檔其.cs內容如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace LoadedXAML
{
public partial class execAnimation : UserControl
{
public execAnimation()
{
InitializeComponent();
}

private void whenLoaded(object sender, RoutedEventArgs e)
{
anima.Begin();
}

}
}




5、主xmal檔請加入一個Button元件:

<Button x:Name="Button_LOAD" Width="100" Height="60"
  Content="Load" Click="doLoad" />

其.cs內容需加入「doLoad」function,程式內容如下:

private void doLoad(object sender, RoutedEventArgs e)
{
 UserControl myCtrl = new LoadedXAML.execAnimation();
 Grid myGrid = (Grid) this.FindName("LayoutRoot");
 myGrid.Children.Add(myCtrl);
}


程式的兩個Project已建立連結,主Project在按下Button後將能夠取得先前新增的xmal檔內容。

2009年12月15日 星期二

Silverlight:Set Color、Set Margain

建立一個名為「newRect」的Rectangle元件,在cs檔中指定Rectangle裡 Fill的顏色值如下:

 Color newColor = Color.FromArgb(255, 0xEE, 0xEE, 0xEE);
 newRect.Fill = new SolidColorBrush(newColor);

或者在new一個Rectangle時你也可以這樣做:

 Color newColor = Color.FromArgb(255, 0xEE, 0xEE, 0xEE);
Rectange rect =
  new Rectange() { Fill = new SolidColorBrush(newColor)};


指定Margin上、下、左、右的方式如下:

 Thickness newTk = new Thickness();
 newTk.Top = (double)5;
 newTk.Left = (double)5;
 newTk.Right = (double)5;
 newTk.Bottom = (double)5;
 newRect.SetValue(Rectangle.MarginProperty, newTk);

SilverLight:指定Grid某一欄位的寬、高

1、在xmal檔中,對目標欄位設定「x:name」,例如:

<Grid x:Name="PS_Container" Visibility="Visible" Height="500">
 <Grid.ColumnDefinitions>
  <ColumnDefinition x:Name="container_Grid_Width1" Width="1*"/>
  <ColumnDefinition x:Name="container_Grid_Width2" Width="4*"/>
  <ColumnDefinition x:Name="container_Grid_Width3" Width="6*"/>
 </Grid.ColumnDefinitions>
</Grid>

在cs檔中,指定寬度的方式(以下分別指定Colunm1、Colunm2、Colunm3):

 GridLength gl = new GridLength(82);
 container_Grid_Width1.Width = gl;
 gl = new GridLength(328);
 container_Grid_Width2.Width = gl;
 gl = new GridLength(Application.Current.Host.Content.ActualWidth - 410);
 container_Grid_Width3.Width = gl;


以上將欄位寬度分成82、328、(410-328-82)等大小,其中Application.Current.Host.Content.ActualWidth能夠取得目前頁面的實際寬度。

Silverlight:讓Button能夠使用 MouseLeftButtonDown & Up

Silverlight在使用Button時,只有「Click」事件能夠產生動作,而「MouseLeftButtonDown」及「MouseLeftButtonUp」…等多個Mouse動作都無作用。
在某些狀況下我們可能需要「MouseDown」及「MouseUp」配合使用,針對這項需求,可使用以下方式解決--

在此以RepeatButton舉例:
對xmal檔中的button物件指定「Click」、「MouseLeftButtonDown」、「MouseLeftButtonUp」等事件,並設定「ClickMode」為「Hover」:

<RepeatButton  Opacity="0.01" Width="24" Height="26" Interval="100"
  Margin="-8" ClickMode="Hover"
  Click="on_tomorrow" MouseLeftButtonDown="on_tomorrow_down"
  MouseLeftButtonUp="on_tomorrow_up"/>

在cs檔中寫前對應的function。將「ClickMode」設定為「Hover」時,只要mouse置於button上就會觸發Click事件,mouse置於button上時,以一個bool變數去判斷mouse是不是Down的狀態,即可使用MouseLeftButtonDown及MouseLeftButtonUp的功能:

 bool butmDown = false;
 private void on_tomorrow(object sender, RoutedEventArgs e)
 {
  if (!butmDown) return;
  …//when mouse down, do something on this code..
  …
 }
 private void on_tomorrow_down(object sender, MouseButtonEventArgs e)
 {
  butmDown = true;
 }
 private void on_tomorrow_up(object sender, MouseButtonEventArgs e)
 {
  MessageBox.Show("release mouse");
  butmDown = false;
 }

C#:Silper 運用--以指定tag拆解字串

string下的「Splite」方法,能夠指定特定的字元,將一個字串分解成一組字串陣列,例如以下程式內容會以MessageBox顯示a、b、c、d、e、f、g:

 string strData = "a;b;c;d;e;f;g";
string[] separator = new string[] { ";" };
 string[] strSplitArr =
  strData.Split(separator, StringSplitOptions.RemoveEmptyEntries);
 foreach (string arrStr in strSplitArr)
 {
  MessageBox.Show(arrStr);
 }

再者,以下內容能夠產生「Apple」、「Banana」、「Cantaloupe」:

 string[] separator = new string[] { "[", "]" };
 string[] strSplitArr =
  strData.Split(separator, StringSplitOptions.RemoveEmptyEntries);
 foreach (string arrStr in strSplitArr)
 {
  MessageBox.Show(arrStr);
 }

或者有必要時,使用[Fruit] + [/Fruit]來將字串拆解成「Apple」、「Banana」、「Cantaloupe」:

 string strData =
  "[Fruit]Apple[/Fruit][Fruit]Banana[/Fruit][Fruit]Cantalopue[/Fruit]";
 string[] separator = new string[] { "[Fruit]", "[/Fruit]" };
 string[] strSplitArr =
  strData.Split(separator, StringSplitOptions.RemoveEmptyEntries);
 foreach (string arrStr in strSplitArr)
 {
  MessageBox.Show(arrStr);
 }

2009年12月7日 星期一

Silverlight: Cookie的使用

首先需要引用…

using System.Windows.Browser;


寫入cookie:以下內容會將「Key=Nothing」寫入cookie中

DateTime expiration = DateTime.UtcNow + TimeSpan.FromDays(2000);
string cookie = String.Format("{0}={1};expires={2}",
      "Key", "Nothing", expiration.ToString("R"));
HtmlPage.Document.SetProperty("cookie", cookie);


刪除cookie內容值:以下內容會將「Key」值移除
 DateTime expireDate = DateTime.Now - TimeSpan.FromDays(1);
 string expires = ";expires=" + expireDate.ToString("R");
 string cookie = "Key=" + expires;
 HtmlPage.Document.SetProperty("cookie", cookie);


讀取cookie內容值:以下將會找出「Key」的內容值,並以MessageBox提示
 String[] cookies = HtmlPage.Document.Cookies.Split(';');
 string key = "Key=";
 foreach (string s in cookies)
 {
  string ck = s.Trim();
  if (ck.StartsWith(key, StringComparison.OrdinalIgnoreCase))
  {
   string[] vals = ck.Split('=');
   MessageBox.Show(vals[1]);
  }
 }

2009年12月3日 星期四

Silverlight、C#:Post in HttpWebRequest

以下主要在從事Silverlight做Web Request,以Post對Server要求資料時用上:

 WebClient wc_DoLogin = new WebClient();
wc_DoLogin.UploadStringCompleted += new
   UploadStringCompletedEventHandler(wc_DoLogin_UploadStringCompleted);
 wc_DoLogin.Headers["content-type"]
   = "application/x-www-form-urlencoded";
 wc_DoLogin.UploadStringAsync(
  new Uri(Url, UriKind.Absolute),
  "POST",
  "欄位1=欄位值&欄位2=欄位值2");

Server回應將會在wc_DoLogin_UploadStringCompleted被接收:

void wc_DoLogin_UploadStringCompleted
(object sender, UploadStringCompletedEventArgs e)
{
MessageBox.Show("result is : " + e.Result);
}

2009年11月23日 星期一

Silverlight:Grid劃份區域 & 動態裁切範圍(Grid 、Clip 的使用)

本篇主要說明在C#內指定裁切範圍,順便提一下以「*」來指定Grid範圍的方法(基本上...這兩樣東西是可以分開說明)。


首先準備好Grid:

<Grid x:Name="LayoutRoot" Loaded="doClip" Width="400" Height="200">

  <Rectangle Width="400" Height="200" Fill="Red"/>
  <Grid ShowGridLines="True" x:Name="GridToClip" >
    <Grid.ColumnDefinitions>
     <ColumnDefinition Width="2*"/>
     <ColumnDefinition Width="5*"/>
    </Grid.ColumnDefinitions>
    <Ellipse Width="50" Height="50"
      Fill="Green" Grid.Column="1">
    <Ellipse.RenderTransform>
     <TranslateTransform X="-150"/>
    </Ellipse.RenderTransform>

    </Ellipse>
  </Grid>
</Grid>

以上使用Grid.Column將區域分成兩個部份,其中並沒有使用Grid.Clip元件對任何一個區域做裁切的動作。

另外在指定 Column各別寬度的部份,『Width="2*"』及『Width="5*"』將Grid總算度以 2:5 的比例做分配,Column為1(第二欄)的地方置放一個Ellipse元件,並橫跨第一欄及第二欄,當裁切完成時,我們可以明白分辦裁切的效果。

接著在頁面載入時加入以下程式,可指定裁切屬性及範圍:

private void doClip(object sender, RoutedEventArgs e)
{
 GridToClip.Clip = new RectangleGeometry()
 {
  Rect = new Rect(0, 0, 200, 100)
 };
}

其中

  new Rect(0,0,200,100)

紅字部份分別指定double型態的Top、Left、Bottom、Right

2009年11月18日 星期三

Silverlight:正確執行 HTTP Request(POST/GET)

在網路上使用POST或GET方式對伺服器要求服務簡是很普遍的行為,以下介紹在Silverlight上從事此行為的步驟。

☆要傳送一個POST/GET的動作,Silverlight有兩種方式:
1、WebClient
2、HttpWebRequest

本篇先介紹 WebClient

☆除了程式內容以外,在server端需要額外做一個步驟,才能使得Silverlight正常做到POST/GET的動作:
在server端設置「clientaccesspolicy.xml」或「crossdomain.xml」,兩者擇一即可,兩個xml的內容稍後會描述。


可直接在程式執行階段鍵入以下程式內容,建立WebClient:

WebClient wc = new WebClient();
wc.DownloadStringCompleted +=
  new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
Uri uri =
  new Uri("http://2.latest.te-web-database.appspot.com
  /getTeacherIdByClassIdByWeb?aClassId=Creat");


wc.DownloadStringAsync(uri);

上述程式碼內紅字部份,請依據使用者欲連結的伺服器網域,輸入網域位置及POST/GET的內容,簡單說明程式步驟如下:
1、建立 WebClient物件(new WebClient)。
2、完成POST/GET動作後,建立欲導入的function(wc.DownloadStringCompleted += ...)。
3、建立Uri物件(Uri uri = new Uri(xxx))。
4、執行(wc.DownloadStringAsync(uri))。

另外別忘了建立DownloadStringCompleted所指定的function內容:

void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error == null)
{
MessageBox.Show(e.Result);
}
else
{
MessageBox.Show("else");
}
}

如果使用WebClient的方式,POST/GET成功後的回傳值將會在上一段程式的「e.Result」內。


執行httpRequest前最重要的事情,需將「clientaccesspolicy.xml」或「crossdomain.xml」設置到 Domain的根目錄(參考頁:http://community.dynamics.com/blogs/cesardalatorre/comments/9579.aspx):

選擇1、建立clientaccesspolicy.xml檔案,檔案內容如下:

<?xml version="1.0" encoding="utf-8"?>
 <access-policy>
  <cross-domain-access>
  <policy>
  <allow-from http-request-headers="*">
   <domain uri="*"/>
  </allow-from>
   <grant-to>
    <resource path="/" include-subpaths="true"/>
   </grant-to>
  </policy>
 </cross-domain-access>
</access-policy>


選擇2、建立crossdomain.xml檔案,檔案內容如下:

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy
  SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
  <allow-http-request-headers-from domain="*" headers="*"/>
</cross-domain-policy>


以上兩個xml只需選擇一個,置於Domain的根目錄下,以本篇例子來說,就該將xml檔案放在「http://2.latest.te-web-database.appspot.com」之下。

2009年11月11日 星期三

Silverlight:在C#中改變Image の Source

以C#程式去改變一個Silverlight Image元件的Source屬性,這裡以兩張 png圖檔的變換來做範例。

首先請任意準備好兩張圖片檔案,各別取名為"enter.png"及"leave.png",在xaml檔案的<Grid>內加入以下敘述:

<Image x:Name="img" Source="leave.png" Width="100" Height="100"
  MouseEnter="enter" MouseLeave="leave">


為正常使用BitmapImage功能,在 cs檔開頭using部份加入以下敘述:

using System.Windows.Media.Imaging;

當滑鼠進入圖片範圍將會執行enter函式,離開圖片範圍則執行leave函式,兩個函式內容如下:

private void enter(object sender, MouseEventArgs e)
{
BitmapImage newImg =
       new BitmapImage(new Uri("enter.png", UriKind.Relative));
img.Source = newImg;
}

private void leave(object sender, MouseEventArgs e)
{
BitmapImage newImg =
       new BitmapImage(new Uri("leave.png", UriKind.Relative));
img.Source = newImg;
}


加入System.Windows.Media.Imaging後方可使用BitmapImage class,變換圖片的動作才能夠正常執行。

2009年11月10日 星期二

Silverlight:漸變顏色梯度

在Silverlight使用顏色梯度對元件的Fill屬性做設定已很平常,在效果的運用上,這裡介紹使物件漸淡的設定方法。



上圖由程式繪制出兩個<Rectangle>元件,其中一個使用線性漸變的顏色梯度設定,程式敘述如下:

<Grid x:Name="LayoutRoot">
  <Rectangle Width="200" Height="50" Fill="White"/>           
  <Rectangle Width="100" Height="100" Opacity="0.9" Grid.Row="1"
     Grid.Column="0" RadiusX="10" RadiusY="10">
    <Rectangle.RenderTransform>
      <TranslateTransform X="5" Y="-3"/>
    </Rectangle.RenderTransform>
    <Rectangle.Fill>
     <LinearGradientBrush EndPoint="0.7,0.5" StartPoint="0,0.5" >
       <GradientStop Color="#00000000" Offset="1"  />
       <GradientStop Color="#FF000000" Offset="0"/>
     </LinearGradientBrush>
    </Rectangle.Fill>
  </Rectangle>
</Grid>

這樣的設定,在元件可能被任意移動時,可做到將物件動態漸淡的效果。設定方法主要在顏色屬性的EndPointStartPoint數值、Color數值中Alpha值由FF至00互相調整,就能做到這樣的效果。(註:Alpha值指的即是 #FF000000中紅字部份的值)

2009年11月6日 星期五

Silverlight:Children使用Grid

先看到以下Silverlight敘述:

<Grid x:Name="LayoutRoot" Height="400" Width="800"
      ShowGridLines="True" Background="White">
  <Grid.RenderTransform>
    <TransformGroup>
      <TranslateTransform X="0" Y="10" />
    </TransformGroup>
  </Grid.RenderTransform>
  <Grid.RowDefinitions>
    <RowDefinition />
    <RowDefinition />
  </Grid.RowDefinitions>
  <Grid.ColumnDefinitions>
    <ColumnDefinition />
      <ColumnDefinition />
      <ColumnDefinition />
    </Grid.ColumnDefinitions>
  <Canvas x:Name="box1" Grid.Row="0" >
    <Canvas.RenderTransform>
      <TranslateTransform X="35" Y="10"/>
    </Canvas.RenderTransform>
      <Rectangle Width="100" Height="100" Fill="Red" Grid.Column="1"/>
  </Canvas>

</Grid>



在某些情況下(例如動態排列物件位置)使用Grid元件時,當我們將要將Silverlight元件丟進名為box1的Canvas物件內,並設定其位置到Grid的第1行第2列時(Row=0、Column=1),將物件置入box1後,直接在該物件上設定Grid.Row的屬性將行不通,例如:

<Canvas x:Name="box1" Grid.Row="0" >
  <Canvas.RenderTransform>
    <TranslateTransform X="35" Y="10"/>
  </Canvas.RenderTransform>
    <Rectangle Width="100" Height="100" Fill="Red" Grid.Column="1"/>
</Canvas>

以上敘述的Rectangle物件將不會被設定至Grid(0,1)的位置。而是乖乖的待在其所屬的parent Canvas元件的起始位置。

將以上<Grid>內改改變如下:

<Grid x:Name="LayoutRoot" Height="400" Width="800" Background="White">
  <Grid.RenderTransform>
    <TransformGroup>
      <TranslateTransform X="0" Y="10" />
    </TransformGroup>
  </Grid.RenderTransform>

  <Grid.RowDefinitions>
    <RowDefinition />
    <RowDefinition />
  </Grid.RowDefinitions>

  <Canvas x:Name="box1" Grid.Row="1" Grid.Column="1" >
    <Canvas.RenderTransform>
      <TranslateTransform X="0"/>
    </Canvas.RenderTransform>
    <Grid ShowGridLines="True" Width="870" x:Name="privateGridBox">
      <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
        <ColumnDefinition />
       </Grid.ColumnDefinitions>
    </Grid>
  </Canvas>

</Grid>

將Silverlight元件置於在上敘box1元件的<Grid>內,可正常使用Grid功能。

2009年11月4日 星期三

Silverlight:使用元件內無指定的屬性,可能產生的問題

在從事修改Sliverlight內各元件的屬性,假若在.xaml檔內的元件沒有先行加入屬性的敘述,程式執行時,將無指對該屬性從事修改的動作(元件內無法找到指定的屬性),例如以下Ellipse元件:

<Ellipse x:Name="MyAnimatedRectangle" Stroke="Black" StrokeThickness="1"
  Width="50" Height="50" >

</Ellipse>


程式在執行中,若想使用 PlaneProjection對當下的Ellipse元件指定RotationX屬性值,則會發生找不到指定屬性的狀況。其解決方法即是在目標Ellipse內加入Projection內容(物件內必需被包入指定的屬性值,亦即程式執行當中再加入亦可):

<Ellipse x:Name="MyAnimatedRectangle" Stroke="Black" StrokeThickness="1"
  Width="50" Height="50" >
    <Ellipse.Projection>
     <PlaneProjection x:Name="pProject" RotationX="0" RotationY="0"/>
    </Ellipse.Projection>

</Ellipse>

假若沒有預先加入<Prjection>內容,程式執行屬性修改前加入以下程式碼亦可:

MyAnimatedRectangle.Projection = new PlaneProjection();

Silverlight:使物件移動至指定座標(RenderTransform)

開啟一個Silverlight專案(C#)後,在.xaml檔加入以下內容,產生一個Grid(即將以下內容整個放在<UserControl>及</UserControl>之間,若已有Grid,取代之):

  <Grid x:Name="LayoutRoot" Background="white" Width="450" Height="450">
        <Canvas Background="Red" x:Name="canvasForBackground" MouseLeftButtonDown="getMousePosition">
            <Canvas.Resources>
                <Storyboard x:Name="moveEllipse">
                    <DoubleAnimation x:Name="moveEllipse_moveX" 
           Storyboard.TargetName="MyAnimatedRectangle"
           Storyboard.TargetProperty="(Ellipse.RenderTransform).X"
                                     From="10" To="100" Duration="0:0:1"/>
                    <DoubleAnimation x:Name="moveEllipse_moveY" 
           Storyboard.TargetName="MyAnimatedRectangle"
           Storyboard.TargetProperty="(Ellipse.RenderTransform).Y"
                                     From="10" To="100" Duration="0:0:1"/>
                </Storyboard>
            </Canvas.Resources>
            <Ellipse x:Name="MyAnimatedRectangle" Stroke="Black"
         StrokeThickness="4" Fill="Red" Width="50" Height="50" >
                <Ellipse.RenderTransform>
                    <TranslateTransform X="200" Y="200"/>

                </Ellipse.RenderTransform>
            </Ellipse>
        </Canvas>
    </Grid>


上述內容中,有先設定好的Silverlight元件動畫:

            <Canvas.Resources>
                <Storyboard x:Name="moveEllipse">
                    <DoubleAnimation x:Name="moveEllipse_moveX"  Storyboard.TargetName="MyAnimatedRectangle" Storyboard.TargetProperty="(Ellipse.RenderTransform).X"
                                     From="10" To="100" Duration="0:0:1"/>
                    <DoubleAnimation x:Name="moveEllipse_moveY"  Storyboard.TargetName="MyAnimatedRectangle" Storyboard.TargetProperty="(Ellipse.RenderTransform).Y"
                                     From="10" To="100" Duration="0:0:1"/>
                </Storyboard>
            </Canvas.Resources>



在同一個Storyboard中,可以加入兩個DoubleAnimation(如上述Storyboard包函了「moveEllipse_moveX」、「moveEllipse_moveY」兩個DoubleAnimation),當名為「canvasForBackground」的Canvas元件被按下後,會進入getMousePosition函式,觸發此Storyboard動畫,相對應的C#程式內容如下:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Browser;

namespace MoveWithMouse
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}

private void getMousePosition(object sender, MouseButtonEventArgs e)
{
TranslateTransform tt =
MyAnimatedRectangle.RenderTransform as TranslateTransform;
Point pos;
pos = e.GetPosition(canvasForBackground);
moveEllipse_moveX.From = tt.X;
moveEllipse_moveX.To = pos.X - 25;
moveEllipse_moveY.From = tt.Y;
moveEllipse_moveY.To = pos.Y - 25;
moveEllipse.Begin();
}
}
}


其中「moveEllipse_moveX」即是.xaml檔中,Storyboard之下其中一個DoubleAnimation的名字,在程式中將其「From」的屬性改為當下Silverlight元件的位置。
其中有一行如「 moveEllipse_moveX.To = pos.X - 25;」,其需要減去25的原因在於此Ellipse元件的Width值為50,減去25之後,元件移動後,元件中心才會正確到達指定點。

Silverlight:簡單的3D屬性控制(RotationX、Y、Z))

開啟一個Silverlight專案(C#)後,在.xaml檔加入以下內容,產生一個Grid(即將以下內容整個放在<UserControl>及</UserControl>之間):


   <Grid x:Name="LayoutRoot" Width="450" Height="450" >
        <Canvas Background="Red" x:Name="canvasTop"
                MouseLeftButtonDown="getMousePosition" MouseMove="mouseMove" MouseLeave="unmouseDown" MouseLeftButtonUp="unmouseDown">
            <Ellipse x:Name="MyAnimatedRectangle" Stroke="Black" StrokeThickness="1"
                     Width="50" Height="50" >
                <Ellipse.Projection>
                    <PlaneProjection x:Name="pProject" RotationX="0" RotationY="0"/>
                </Ellipse.Projection>
                <Ellipse.RenderTransform>
                    <TranslateTransform X="200" Y="200"/>
                </Ellipse.RenderTransform>
                <Ellipse.Fill>
                    <LinearGradientBrush EndPoint="0.2,1" StartPoint="0.5,0">
                        <GradientStop Color="Black" Offset="0"/>
                        <GradientStop Color="#FFEEC5C5" Offset="1"/>
                    </LinearGradientBrush>
                </Ellipse.Fill>
            </Ellipse>
        </Canvas>
    </Grid>



上述的xaml內容,在名為canvasTop的Canvas元件中有四個mouse事件,即「MouseLeftButtomDown」、「MouseLeftButtonUp」、「MouseMove」、「MouseLeave」。事件發生時觸發的function:

MouseLeftButtomDown → getMousePosition()
MouseLeftButtonUp、MouseLeave → unmouseDown()
MouseMove → mouseMove()

與其對應的 .cs檔,程式內容如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace Rotation3D_OnMouse
{
public partial class MainPage : UserControl
{
bool onMouseDown = false;//if mouse click on canvas
Point currentPosition;
Point nextPosition;

public MainPage()
{
InitializeComponent();
}

private void getMousePosition(object sender, MouseButtonEventArgs e)
{
onMouseDown = true;
currentPosition = e.GetPosition(canvasTop);
}

private void mouseMove(object sender, MouseEventArgs e)
{
if (!onMouseDown) return;

nextPosition = e.GetPosition(canvasTop);
PlaneProjection pp = MyAnimatedRectangle.Projection as PlaneProjection;
double tmpX = nextPosition.Y - currentPosition.Y;
double tmpY = nextPosition.X - currentPosition.X;
pp.RotationX = tmpX;
pp.RotationY = tmpY;
}

private void unmouseDown(object sender, MouseEventArgs e)
{
onMouseDown = false;
}
}
}



觸發MouseLeftButtonDown後做MouseMove的動作,可對Silverlight目標物件做RotationX、RotationZ的動作。

2009年10月29日 星期四

SilverLight:簡單的Silverlight連續動作(animation)

本篇內容將提到如何使用SilverLight的animation

主要步驟:
a.開啟Silverlight專案
b.新增SilverLight幾何元件
c.編寫animation程式內容

1、開啟一個新的SilverLight專案後,在主要的 xmal 檔中先找到<UserControl>,並在此tag先加入幾個Silverlight元件,在加入Silverlight元件前,我們要求元件做整齊的排列,所以額外請加入一個Grid來排列每個元件。

2、下述<Grid>使用<Ellipse>元件來從事animaltion的動作,我們會對每個<Ellipse>元件加入一個 'onMouseLeftDown' 的屬性,當此元件被按下時,將會觸發 leftDown( ) 函式,以下為需加入xmal檔內<UserControl>的描述。

<Grid x:Name="LayoutRoot">

        <Grid.RowDefinitions>

            <RowDefinition Height="80"/>

        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="80"/>

            <ColumnDefinition Width="80"/>

            <ColumnDefinition Width="80"/>

            <ColumnDefinition Width="80"/><!--3-->

            <ColumnDefinition Width="80"/>

            <ColumnDefinition Width="80"/>

            <ColumnDefinition Width="80"/><!--6-->

            <ColumnDefinition Width="80"/>

            <ColumnDefinition Width="80"/><!--8-->

        </Grid.ColumnDefinitions>


        <Ellipse x:Name="e0_0" Width="40" Height="40" StrokeThickness="2" Grid.Row="0" Grid.Column="0"

                 MouseLeftButtonDown="leftDown" >

            <Ellipse.Fill>

                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">

                    <GradientStop Color="#FFFF7100" Offset="0"/>

                    <GradientStop Color="Yellow" Offset="1"/>

                    <GradientStop Color="#9A86B741" Offset="0.664"/>

                </LinearGradientBrush>

            </Ellipse.Fill>

            <Ellipse.Stroke>

                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">

                    <GradientStop Color="Black" Offset="0"/>

                    <GradientStop Color="#FFC5B133" Offset="1"/>

                </LinearGradientBrush>

            </Ellipse.Stroke>

        </Ellipse>

        <Ellipse x:Name="e0_1" Width="40" Height="40" StrokeThickness="2" Grid.Row="0" Grid.Column="1"

                 MouseLeftButtonDown="leftDown">

            <Ellipse.Fill>

                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">

                    <GradientStop Color="#FFFF7100" Offset="0"/>

                    <GradientStop Color="Yellow" Offset="1"/>

                    <GradientStop Color="#9A86B741" Offset="0.664"/>

                </LinearGradientBrush>

            </Ellipse.Fill>

            <Ellipse.Stroke>

                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">

                    <GradientStop Color="Black" Offset="0"/>

                    <GradientStop Color="#FFC5B133" Offset="1"/>

                </LinearGradientBrush>

            </Ellipse.Stroke>

        </Ellipse>

    </Grid>



 



3、將以上內容需描述在<UserControl>內之後,接著編輯產生animation的程式內容:

private void leftDown(object sender, MouseButtonEventArgs e)
{
Shape s = (Shape)sender;

DoubleAnimation da = new DoubleAnimation();
da.SpeedRatio = 8;
da.From = 40;
da.To = 80;
da.AutoReverse = true;
DoubleAnimation daY = new DoubleAnimation();

daY.SpeedRatio = 8;
daY.From = 40;
daY.To = 80;
daY.AutoReverse = true;

Storyboard sb = new Storyboard();
Storyboard.SetTargetProperty(da, new PropertyPath("(Shape.Width)"));
Storyboard.SetTargetProperty(daY, new PropertyPath("(Shape.Height)"));

Storyboard.SetTarget(sb, s);
Storyboard.SetTargetName(sb, s.Name);//set target name
sb.Children.Add(da);
sb.Children.Add(daY);

sb.Completed += new EventHandler(sb_Completed);
sb.Begin();
}


4、以上敘述為<Ellipse>被按下後,C# 會取得xmal內被觸發此event的元件,將此元件的'Height'屬性及'Width'屬性從40變化至80。

5、其中加入「sb.Complete += new EventHandler(sb_Completed);」,當動作結束後,將會觸發sb_Completed( )這個函式。

6、xmal的敘述中,你會發現每個<Ellipse>元件的命名是有規則的,此用意是為了連續動作的方便而將元件的命名規則化,所以務必在程式中加入下列敘述,以方便在動作結束後,sb_Completed( )敘述能夠取得當下觸發event的元件:

Storyboard.SetTargetName(sb, s.Name);//set target name

7、以下為 sb_Completed( )函式以及 endObj( ) 函式內容:

void sb_Completed(object sender, EventArgs e)
{
string str = Storyboard.GetTargetName(sender as Storyboard);
Shape s = this.FindName(str) as Shape;
string sRow = s.Name.Substring(1, 1);
string sCol = s.Name.Substring(s.Name.Length - 1, 1);
int tmpInt = Int32.Parse(sCol);
tmpInt += 1;
sCol = tmpInt.ToString();
str = "e" + sRow + "_" + sCol;
s = this.FindName(str) as Shape;
if (s != null)
{
nextObj(s,e);
}
else
{
MessageBox.Show("end of shape object !!");
}
}


8、這裡所謂的連續動作,指的是將程式內所有的Silverlight元件以順序而連續animation的方式一一動作。故按下其中一個Silverlight元件後,程式會依序往後抓取下一個<Ellipse>元件,以下請額外加入 nextObj( )函式。

void nextObj(object sender, EventArgs e)
{
Shape s = (Shape)sender;

DoubleAnimation da = new DoubleAnimation();
da.SpeedRatio = 8;
da.From = 40;
da.To = 80;
da.AutoReverse = true;
DoubleAnimation daY = new DoubleAnimation();
daY.SpeedRatio = 8;
daY.From = 40;
daY.To = 80;
daY.AutoReverse = true;

Storyboard sb = new Storyboard();
Storyboard.SetTargetProperty(da, new PropertyPath("(Shape.Width)"));
Storyboard.SetTargetProperty(daY, new PropertyPath("(Shape.Height)"));

Storyboard.SetTarget(sb, s);
Storyboard.SetTargetName(sb, s.Name);//set target name
sb.Children.Add(da);
sb.Children.Add(daY);

sb.Completed += new EventHandler(sb_Completed);
sb.Begin();
}

2009年10月13日 星期二

SVG技巧:正常執行SVG拖曳の動作

Javascript Event 的使用

Javascript中,事件處理常常用到如onmouseclick、onmousemove、onmouseup等動作,在SVG圖象上運用非常頻繁。而使用以上event最簡單的方式即是直接在SVG物件的描述中加入:

onmousedown="function( )"、onmousemove="function( )"、onmouseup="function ( )"

例如在一個SVG四方體物件中:

<rect x="0" y="0" width="100" height="60" fill="red" onmousedown="downFunc()"/>

上述物件就會在被使用者點擊時觸發 downFunc( ) 這個函式。

拖曳動作
1、這裡所謂的「拖曳動作」指的是「按下後隨即移動」的動作,即「mouse down than move」的動作。
2、拖曳動作運用在SVG圖象上會有一種狀況是「SVG圖象被當作是圖片」。使用Firefox對SVG物件做拖曳時,若動作太快(即點擊物件後隨即移動),會被視為「抓取此SVG圖象」的動作。
3、假若程式原本的動作是想要「定點移動SVG圖象」,而非抓取SVG圖象,瀏覽器所產生的錯誤動作實為一大誤會(簡單說就是瀏覽器太雞婆....)。

解決方案一(隱藏後顯示):
說明:
1、即對SVG內容『setAttribute("display","none") 』後,接著『setAttribute("display","inline")』。
2、需注意的是,假若隱藏後隨即顯示將會沒有效果,無法完成原本預期要的動作。
3、需要間隔一小段時間,再將隱藏後的SVG圖象回愎顯示(可使用setTimeout( )來完成)。
4、需配合物件copy的方式來完成。由於主SVG物件從隱藏回愎到顯示時,會明顯發現物件有「閃爍」的動作,感覺非常不自然,在此使用副物件的方式,來製造主物件的分身,產生「無閃爍」的假像。
5、在主SVG物件被隱藏後,滑鼠對於主物件的Focus將會被解除。這樣一來即可避開「抓圖」的問題。

實行方式
Copy Sub Content:對將被拖曳的SVG圖象使用『cloneNode(true)』如:
  var subSVGObj = SVGObj.cloneNode(true);
  subSVGObj.setAttribute("display","none");
上述程式內容是對目標SVG圖象Copy一份相同的內容至subSVGObj內(記得預設為隱藏),接下來有兩個動作:
  隱藏主SVG內容
  function contentHide(){
    subSVGObj.setAttribute("display","inline");
    SVGObj.setAttribute("display","none");
  }
  回愎顯示主SVG內容
  function contentShow(){
    SVGObj.setAttribute("display","inline");
    subSVGObj.setAttribute("display","none");    
  }
步驟:
當onmousedown產生作用時:

  contentHide( );
  setTimeout("contentShow( )",100);

上述描述即「先隱藏主SVG物件,顯示副SVG物件,0.1秒後再回愎」。

2009年9月24日 星期四

RFB -- VNC的基礎

RFB (Remote Framebuffer)
為一種簡單的遠端存取協定,讓使用者以圖像的方式存取遠端電腦。此協定運作於Framebuffer層級,因此能夠應用於所有的視窗介面,其包括X11、Windows及Macintosh。VNC即是RFB協定一種應用。
要求連線,並得到遠端畫面的一方稱之為Client或是Viwer,對相的另一端稱之為RFB Server。RFB實為一種「Thin-Client」的協定,此重點在於建立一個功能上需求極精簡的Client,在這方面,Client可以應用於更廣泛的硬體上,而Client的功能愈簡單愈好。  RFB協定同時使得Client成為一種「stateless」的形態,假若Client中斷連結後,隨及再度連結同個Server,Client端的畫面將會保留。此外,不同的Client允許對同樣的RFB Server做連結。在新的端點上的使用者會看到與Server主機相同的畫面,實際上,這樣的介面讓使用者更能夠任意的改變位置。不論如何,只要得到合適的網路連線,使用者就能夠任意存取個人應用軟體,這些應用軟體能夠在兩地之間做到存取的動作,不過何處,都能提供使用者熟悉的、客製化的視覺基礎。

RFB內容還包括了以下各式協定:

Display Protocol
顯示協定的基礎圍繞在原始單一圖像(single graphics primitive):
  『將某區塊的像素資料,設定至(x,y)位置上』
在最初看來,以這種方式繪出使用者介面似乎會是個無效率的方法。然而,允許多種不同的編碼方式,對於像素資料處理中,交換參數值方面得到了相當大的使用彈性,例如頻寬、Client繪圖速度、Server 處理速度等。  給定一串序列的資料可對Framebuffer做更新的動作。而每一次的更新,都會將舊有的Framebuffer更動至另一種狀態,這方面有點類似一段影片中的影格(Frame),基本上每個區塊都不會相交,但還是會有不一定的狀況出現。  更新協定為一種「需求導向」的協定,意思是說「在Client要求更新時,訊息只會由Server發送」,這方式使得此協定能有最合適的通訊品質,慢速Client會更新的較慢。一般應用程式在Framebuffer相同區段改變時,會變換的較其他區段來的快速,若是在傳輸緩慢的網路中,Framebuffer的更新可能會被乎略掉。

Input protocol
輸入以標準工作工如鍵盤、多按鈕裝置為主。Client在任意地點,按下按鍵或是點座標裝置移動時,都會對Server發送要求訊息。這些被輸入的訊息亦可由非標準輸入裝置發送,整合為可被Server接受的編碼。

Display pixel data
RFB在開始送傳資料前,Client及Server 會對將被傳送的像素資料的格式及編碼方式做協調,這部份的協調是為了讓Client端的工作愈簡單愈好,Server必需提供Client最基本的像素資料的需求,假若 Client本身能夠應付其他多種編碼方式,Server則會選擇最簡單易行的編碼方式來做傳送的動作。  像素資料包函個別顏色內容,最普遍的顏色格式如「真彩」的24-bit及16-bit,每個bit區段直接轉為RGB對應的強度色彩。  「編碼」(encoding)會影響區段內的像素資料如何傳送,每個像素資料區塊都預先被指定一個(x,y)螢幕位置,而區塊的長、寬、編碼都將被指定在像素資料的資料區塊中,而區塊資料也會依據指定的編碼方式編碼。

Extension protocol
在此有多種方法能夠擴展協定:
新增一個編碼的型態對於現有的Client及Server來說是相對上的容易做到,只不過Server會自動乎略它不支援的新編碼型態,而Client也不會去求要一個新的編碼方式,因此不會產生這種編碼方式的資料區塊。

編碼資料中對於偽編碼(Pseudo Encodings),Client可以對Server要求“pesudoencoding”,宣告其本身支援這一類型的擴充協定;假若Server不支援”pseudo-encoding”則會略乎此編碼。該注意的是Client必需假設Server不支援這類的擴充,直到Client從Server取得真正完成擴充認證。

新的安全型態
協定在新新增一個安全型態時有很大的彈性,而不必擔心Client及Server的相容性問題。當Client及Server 都這同了新的安全型態後,雙方在資料交換方面將更加有效率,並不見得每一項工作都需依照RFB協定。

在任何情況下使用不同版本的協定
RFB協定的版本主要被維護人員定訂,假若你的協定與Server使用了不正確的版本號碼,雙方將無法相容。最重要的一點在於確認RFB協定的相容性,以確保編碼及安全型態不會發生衝突。


協定訊息
RFB協定可以依任何可靠的定協傳送資料 (如TCP/IP),即使byte-streamor。正常來說RFB主要透過TCP/IP達成連線。完成一個RFB協定有三個步驟:第一步為「handshaking phase」,此階段主要是去同意協定的版本及使用的安全型態;第二步為「initialization phase」,即對Server與Client互相交換「ClientInit」及「ServerInit」的訊息。第三步為「normal protocol interaction」,Client將能夠傳送任何它想傳送的訊息,然後接受Server回傳的結果。

協定版本
「Handshaking Phase」開始前,Server會傳送ProtocolVerstion的訊息給Client,使得Client能夠知道Server端支援RFB的最高版本,隨而Client回應Server可使用的版本號碼(不一定與Server的版本號碼相同),正常來說,Client不該要求高於Server端RFB的版本。

安全
一定協定版本確認後,Client、Server在連線時,必需協議共同的安全性標準。假若Client支援的安全性協定有在Server列舉的安全性協定清單中,Client會回傳單一byte的訊息告知Server某安全性協定可被用於這次的連結。  在進行Handshaking Phase時,不論這一階段的連成是否成立,Server都會傳送一個字串通知Client,假若連線成立,RFB協定即進行下一階段──Initialization Phase.
假若安全性連線失敗,Server則傳送一則字串描述此異常,隨後終止連結。

VNC認證
連線時,隨送傳送16位元的VNC認證,而協定資料不做加密的動作。Server會隨機產生一個16 byte的要求Client回應特定的訊息。Client依據Server傳送過來的16 byte編碼為金鑰,並加密回傳此金鑰以回應Server。而此更協定依據項些安全性協定的回應持續進行下去。

訊息初始化
當Client、Server建立安全性連結後,接著會進行初始化層段(initialsation phase)
這個階段,在Client傳送一個「ClientInit」,Server隨即會傳送「ServerInit」訊息。

ClientInit:
Client回應的訊息只有一個「shared-flag」參數,若值非「0」(true),則表式Server試著去持續共享桌面而不對其他的Client端做終止連線的動作,反之,若值為「0」(false),則表示終止其他連線,僅對某Client端提供桌面分享的服務。

ServerInit:
Server 接受ClientInit訊息後,會接著發送ServerInit訊息,此訊息會告知Client端Framebuffer的長、寬、像素格式以及此桌面相關名稱。

Client給Server的訊息內容
由Client所發出的訊息形態如下:
SetPixelFormat
SetEncodings
FramebufferUpdateRequest
KeyEvent
PointerEvent
ClientCutText
此外,其他仍有需要另行定義的訊息形態,需注意的是假如一則訊息形態沒有事先定義在Client的文件中,Client需確定Server傳送此特定的訊息形態後,Client仍能夠有效的支援。

Client端訊息
SetPixelFormat
設定像素資料後,接會會被置入Framebuffer中的FramebufferUpdate,假若Client沒有送出SetPixelFormat資料,Server在送出像素資料時將會依據即定的像素格式(格式請參考文件6.3.2)。
SetEncodings
指定可被Server接受的編碼格式。而設定於送給Server訊息中的編碼格式將會是雙方做連結時,編碼格式的首選,但此編碼不一定會被Server選擇。即使沒有明確指定,像素資料都會以row的方式被傳送。此外,Client可對原始編碼資料做「偽編碼」(pseudo-encodings)的要求,以告知Server本地端支援此類型的擴充,假若Server不支援此「偽編碼」的類型則會直接乎略不使用。需注意的是,Client必需假設Server端不支援Client原始的編碼型態,直到Server認同Client端的原編碼型態後,Client才能夠使用此編碼型態。

FramebufferUpdateRequest
Client端對Server提出請求,以了解Server端寫入Framebuffer中的x-position、y-position、width、height數值。Server會以「FramebufferUpdate」對Client端做回應,但需注意的是,多個FramebufferUpdateRequest可能只會由單一一個FrameBufferUpdate回應。  Server會假設Client不斷的截取存放在Framebuffer中Client所需求的部份(x-position,y-position,width,height),因此Server僅需要對Client傳送不斷更新的部份。  但在某些狀況下,Client遺失某特別需求的部份,Client將傳送一則「FramebufferUpdateRequest」訊息,其中參數incremental幫需設為「0」(false),這會對Server請求傳送某指定的Framebuffer的全部內容。  假若Client沒有遺失Framebuffer中任何必要的部份,則傳送FramebufferUpdateRequest時incremental的內容值將會是非0值(true),假若Framebuffer的內容有所更新,Server亦會傳送一個FramebufferUpdate訊息。這裡需注意的是「雙方發某更新訊息的時間是不固定的」。  在快速網路的狀況下,Client會去範規更新傳送的速度以避免獨佔頻寬。

KeyEvent
假若鍵盤按鍵按下,Framebuffer中Down-flag參數值將會是非0值(true),反之則否。其中由X Window所定義的「keysym」值,被指定用於KeyEvent,作為所謂的按鍵「key」。一般來說,這裡的keysym的key值等同於ASCII所訂定的內容值。keysyms並不容易了解,為了提高keysyms能被廣泛的利用,需要注意以下事項:
1、「shift」的狀態(不論shift是否被按下),在keysym動作時應該被視為「背景執行」。舉例來說,要按下US鍵盤的「#」需要按住「shite + 3」,但UK鍵盤則不需按下shift。假若server端為US鍵盤,想要從使用UK鍵盤的Client接收一個「#」號,Client將不會有shift被按下的動作。在這狀況下,Server為了取得一個「#」而非數字「3」,將會內部將shift設為「已按下」。
2、在keysym中,大小寫的區別常非重要。這不同於某些鍵盤於X Window下將大小寫視為相同的狀況。例如,Server接收keysym值中的大寫「A」時,即使沒有按下shift也該認為是大寫的「A」,這代表的是此時,server內部需假定已按下了shift。
3、Server應該呼略keysyms中的「lcok」,如CapsLock和NumLock,且應該依據不同的狀況來解釋每一個接收到的keysyms字元。
4、不同於shift的其他修飾鍵如「Ctrl」、「Alt」等,一樣需要用來反應keysyms值,要注意的是在keysyms中沒有如「ctrl+a」之類的值,這些值(ctrl、alert)只能在Client按下a後跟著被傳送出去。
5、以Client端來說,當他們按下Ctrl或Alt時同樣會產生keysyms中的某些字元,而Client可能需要另外傳送「Release」事件以確保傳送的keysym值能夠正確被Server了解。例如,在German PC鍵盤上,「Ctrl+Alt+q」會產生「@」,在這狀況下,Client需要為「Ctrl」或「Alt」傳送一個假的「release Ctrl」、「release Alt」訊息給 Server以確保keysym值正確被Server解釋。
6、在X Window裡,「backword tab」並沒有通用的標準,在某些系統裡,shift+tab會產生「ISO Left Tabe」的keysym值,其他系統則可能產生「Back Tab」或僅僅產生「Tab」值,或是由應用程式從shift的狀態來判別「backword-tab」而不是「forward-tab」。在RFB協定採用最後一種方式,Client應該產生shifted Tab而不是ISO Left Tab。然而,為後符合backward-compatible的Client,Server應該懂得判別ISO Left Tab同於另一種shift Tab。
PointerEvent
標示如「點的移動」或「點按鈕的按、放」等。點的位置設定於(x-position,y-position),而目前1~8的按鈕狀態由bits0~7的按鈕遮罩所表示,0代表放開,1代表按下。以滑鼠來說,按鈕1、2、3分別對應至左鍵、中鍵、右鍵等。以有滾輪的滑鼠來說,每一個「向前滾動」的動作都代表按下、放開「按鈕4」,向後滾動則以「按鈕5」來表示。

ClientCutText

Server訊息


Server to client messages
Server傳送給Client的訊息包函在下列變數中:
FramebufferUpdate
SetColourMapEntries
Bell
ServerCutText

需注意的是在傳送一則沒有定義於Server文件中的訊息前,Server需要從Client取得「extension specific」,以確定Client在接收後能夠支援此編碼,對此,通常會對Client要求一個偽編碼(pseudo-encoding)。

FramebufferUpdate
一個FramebufferUpdate的內容主要包函一序列的像素矩陣資料(Client必需將這些像素資料填入Client端的Framebuffer),而這一則命令主要在Client發出FramebufferUpdateRequest後產生,需注意的事Update及UpdateRequest的發送時間並沒有明確的定義。

SetColourMapEntries
像素格式若使用「colour map」時,訊息將會告訴Client端其指定的像素值必需對應至指定的RGB強度。

Bell
觸發Client端的Bell物件(若Client有此物件)

ServerCutText

編碼
文件中所定義的編碼型態包括:
Raw
CopyRect
RRE
Hextile
ZRLE
Cursor pseudo-encoding
DesktopSize pseudo-encoding

各編碼內容:
Raw encoding
此為最簡單的編碼型態。此編碼主要包括width x height像素值(Server端產生的四方體,其長、寬的值),這兩項變數值表示每畫面的像素值,並由左至右做線性排列。所有的RFB Client必需能夠去處理Raw編碼中的像素資料。而RFB Server也應該只以Raw編碼為編碼方式,除非Client要求其他的編碼方式。

CopyRect encoding
CopyRect(copy rectangle)編碼屬於簡單且有效率的編碼方式,能夠於Client在Framebuffer中有相同區塊的像素資料中使用。這項編碼方式會先在填入Rect的X,Y標,這動作將使Framebuffer得到一個位置,隨後Client可以取得Rect的像素資料。這項編碼可以用於Client畫面不斷變動狀況,當使用者移動某視窗,或是捲動視窗捲軸時,更能明顯看出此編碼的效果,但若用於對視窗最佳化、重繪圖像等動作時,就不會有明顯畫面變化的效果。Server對圖像只做一次最正確的傳送是最正確的作法,接著要知道這個圖像先前於Framebuffer的位置(x,y),最後使用CopyRect編碼傳送更新的Framebuffer敘述(subsequent)。

RRE encoding
RRE指rise-and-run-length,其基礎在於模擬一段的二維編碼。RRE編碼所包函的rectangle會以能夠被簡易的繪圖engines有效率而快速繪製的形式到達Client端。  RRE編碼的缺點在於無法適用於複雜的桌面,但仍能使用於某些狀況。RRE編碼的基礎在於分割某像素資料的rectangle成多個副屬的rectangle,每一個副屬的rectangle都包括了各別區塊的像素內容,而將這些副屬的rectangle組合後,將會得到原始的rectangel,這些最適的副屬區塊相對的容易被計算出來。這項編碼包括背景像素值,



Hextile encoding
Hextile編碼為RRE的一種延伸,其將rectangle分成16 x 16的區塊,可令其大小為每邊區塊4 bit,而一個被化分出來的rectangle共16bit。每個rectangle由左上開始往右下計算,先左而右,由上至下,而編碼的內容都會依據先前的rectangel排列模式做排列。假若一個rectangle的寬度並非16的倍數,則最後一個rectangel在劃份後的寬度將會小於16。高度的原理同於寬度。  每個區塊不管以Raw編碼或是RRE編碼都會有背景像素值(background pixel),若背景像素的數值同於前一區塊,則不需特別設定至新的區塊中。另一個狀況:若傳送資料是以Raw編碼,背景像素值則不需要做任何設定。假若所有的副屬區塊(subretangle)都擁有相同的背景像素值,可當做整個區塊的前景顏色像素值,僅做一次性的設定;前景像素可同於背景像素的指定方式,其不需特別設定至區塊中,可從前一個區塊中取得。假若先前的區塊是Raw或是SubrectColored的設定,當下的區塊就不會特別前景像素設定至當下的區塊中,但會以AnySubrects從前一區塊取得前景像素(假定前一區塊已經從更前面的區塊取得前景像素值)。

ZRLE encoding
ZRLE代表的是Zlib1 Run-Length Encoding,擁有Z-lib的壓縮、劃分區塊的能力。在傳送的序列資料中,每個區塊由4 byte長的標頭開始,隨後接著由z-lib壓縮的資料。每個單z-lib序列物件主都會在RFB協定的連結中產生作用,所以編碼、解碼需定訂嚴格的順序。  Z-Lib的資料在解壓後,會產生64 x 64的區塊,其值由左至右、由上至下排列(同於Hextile),若資料的長寬bit數不是64的倍數,則最後一個區塊的長寬將會小於64 bit。  ZRLE利用CPIXEL(compressed pixel)技術,這方法同於一般的像素格式,其中所有的bit由(r,g,b)構成,不管(r,g,b)強度為何,true-colour-flag的值不會是0,bitperpixel的值是32,depth值會在24以下。ZRLE中,一個CPIXEL只會有3 byte的長度,亦可能包函最低顯著或最高顯著的(r,g,b)值。bytePerCPixel為ZRLE中CPIXEL的bytes數。  每個區塊以subbencoding type byte開始,假若區塊編碼的起始byte有做過任何設定,則代表此區塊已運行過或是已被清除等等。區塊最底部的7個位元指定著色的範圍,0代表沒有做任何著色;1代表區塊使用單一色系,2~127表示區塊共使用了多少的顏色。

Pesudo-encodings
Cursor pseudo-encoding
Client若對Server發送這一則指令,即表示Client將有能力在本地端劃出server mouse的位置,這能夠在慢速的連線中明顯提升畫面呈現的效果。Server傳送FreamebufferUpdate時,會同時在Cursor pseudo-encoding設定pesudo-rectangle的內容回應Client的更新要求。pesudo-rectangle的內容包函x-position及y-position,其指出server端Cursor的位置,而width、height分別為Cursor的像素,並依據bitmask來設定資料的內容(所謂的bitmask,其內容主要是由左向右、由上至下對像素值做線性排列。

DesktopSize pseudo-encoding
Client端對Server請求DesktopSize pseudo-encoding以告知本地端可應付Framebuffer中width、height值變動的狀況。Server通常會將這一個pseudo-rectangle設定至最後一個Framebuffer資料的DesktopSize pseudo-encoding中,而此項目中pesudo-rectangle的x-position及y-position會被乎略,width及height值會告知新的Framebuffer大小。

2009年9月17日 星期四

VNC (Virtual Network Computing)

參考文件:
http://www.cl.cam.ac.uk/research/dtg/attarchive/pub/docs/att/tr.98.1.pdf

Thin Clients
VNC追求以「Thin Client」的架構,將用戶端的各項處理程序減至「極小」,Client端可任易對server做connect或disconnect的動作,而不影響server的效能。VNC的Client可於任意地點連上Server,即使是在地球的另一面端,只需使用行動裝置就能夠搖控Server。當然,除了VNC以外,另外如使用Citrix ICA Protocol的各式Thin Cline Application(例如Winframe and Insignia Solutions’ Ntrigue)也能達到這些需求,但這些應用的共同缺點是使用了特有的Protocol,以致產生了跨平臺的問題,VNC則否。

VNC Protocol
VNC底層的技術以非常簡單的Protocol實行GUI遠端存取,以Framebuffer的層級動作,卻可以應用於所有的作業系統、視窗作業系統及應用軟體等,確保任何形式的通訊連結。這項協定可透過如TCP/IP這一類可靠的通訊協定運作,終端使用者中,UI操作者我們可稱之為「VNC Client」或是「viewer」;終端機不斷傳送改變中的Framebuffer則叫做「VNC Server」。VNC確實可稱作是「Thin-Client」的系統架構,其中讓Client端以極少量的需求讓多種裝置得以運作遠端搖控。

初始圖像
在協定中,終端顯示基於最初始的單一圖像:

  產生一個虛擬四邊型物件,並給定一個(x,y)座標

一開始總認為這不是一個很有效率的呈現方式,但以網路頻寬、Client繪圖速度、Server處理速度來說,這方式在參數傳送時卻可能提供較大的彈性。像素資料以簡單的「Left to Right」的序列方式掃摸傳送,所有的VNC用方端必需支援這樣的編碼方式,然後這編碼的使用必需依存Client及Server之間的通訊狀況。
舉例來說,server在「copy-rectangle encoding」時非常簡單而有效率,若Client的Framebuffer已存有相同的的序列時,更可以直接使用已存的內容值。這些編碼只是算單的(x,y)序列。這篇編碼通常產生於使用者改變視窗內容後。
Client必需支援「Copy-rectangle encoding」,Client-Server即可簡單被實現,更加節省頻寬,比傳送原送資料還有更加迅速。  其中有一種狀況,即Client端無法讀取(讀回)已使用過的Framebuffer,此時Client無法傳送先前的編碼。
典型的工作站桌面已固的大量資料如現在的顏色、文字等。最有效的編碼方法是將主要的顏色(背景色)與他不同的產色分開傳送。這裡有多種不同的編碼方式。也許使用JPEG做固有圖像的顯示,或是使用MPEG以影像方式呈現。暫存相同的文字資料,使得圖像在第一次產生改變時,圖像資料可以有效的編碼以快速應付多次的改變。

更新
每次傳送的圖像資料會對Framebuffer內容更新,並對有一個有效的Framebuffer狀況做出變動,換句話說,這個動作相似於影像影格的變換,但與影格不同的地方在於「更新的區域」僅僅為Framebuffer中的一小塊,每個方塊可能使用不同的編碼。Server因此可為為螢幕選擇最適合的傳送方式及適用的頻寬做傳輸。這樣的協定對Client是必要的,Client向Server提出更新的求要,Server因而發送更新後的Framebuffer,所有的視窗的資料在Client最近一次求要之後,會匯整成單一的一筆更新資料,使得協定得到最適資料:速度較慢的Client,更新速度愈慢。在一個網路速度快的環境中,使用者視窗的變化在Client端會有流暢的顯示效果;反之,若使用播接網路,Client要求更新的頻率將會減少,意思是說「慢速度Client,移動視窗的最終結果可能直接呈現出來」。

輸入
VNC協定的輸入端建立於標準的工作站模組之下,鍵盤、多按鈕裝置為主。無論何時,當Client發出按鍵訊息、移動點座標裝置,都會對Server發出訊息。輸入訊息亦可被非標準I/O裝置發送。

連結的建立與結束
建立連結前,Server會對Client使用「challenge-response」的方式請求認證;而Client端的使用者通常需要輸入密碼。接著Server與Client開始交換訊息,洽談視窗大小、像素、編碼方式等等,最後Client會要求Server視窗狀況的更新。由於Client端不需回報「狀態」,任何一方可以直接終斷連結而不會產生異常。

VNC Viewers
此處說的「Viewer」指的即是「Client」,VNC中要產生一個Client是非常容易的事情,原因在於VNC要求「Thin-Client」架構。Client只要求能夠確實做到通訊(TCP/IP),並且擁有直接「顯示畫面」的小功能即可(直接繪出Framebufeer或是透過windowin system繪製)。

VNC Servers
由於VNC架構中,為了讓Client功能愈精簡愈好,因此建立VNC Server會比建立一個VNC Client稍難一些(例如Server必需額外提供Client所需求的Pixel Data 格式)。

2009年9月13日 星期日

簡介RDP(Remote Desktop Protocol)-遠端桌面協定

RDP(Remote Desktop Protocol) Wiki :
http://zh.wikipedia.org/wiki/%E9%81%A0%E7%AB%AF%E6%A1%8C%E9%9D%A2%E5%8D%94%E5%AE%9A

RDP可譯為 Remote Desktop Protocol或Remote Display Protocol,兩者涵義相同,此協定簡單的說就是「微軟遠端桌面服務」。此協定可分為Server及Client兩部份。此外,XP 擔任 RDP Server 預設只能有一個 Client 登入,如果需要多人同時登入需要安裝其他的軟體(WinConnect XP)。Windows 2003 Server 可提供多人同時登入,連線的數量根據購買的連線版權。

以下取自Wiki內容:

使用者(用戶端或稱「本機電腦」)連上提供微軟終端機服務的電腦(伺服器端或稱「遠端電腦」)。大部份的Windows都有用戶端所需軟件。其他作業系統也有這些用戶端軟件,例如LinuxFreeBSDMac OS X。伺服端電腦方面,則聽取送到TCP 3389埠的資料。

與遠端桌面協定相容的用戶端可在多種作業系統上執行,許多Linux系統上甚至將RDP用戶端功能列為核心功能之一。此外,使用者也不一定要有寬頻網路才能連上他們的遠端電腦桌面,RDP即使在56K撥接網路下,都還可以提供每秒更新五到六個畫面的效果。

相較於VNC(Virtual Network Computing) :
藉由網路,可傳送鍵盤與滑鼠的動作及即時的螢幕畫面。VNC與作業系統無關,因此可跨平台使用,例如可用Windows連線到某Linux的電腦,反之亦同。甚至在沒有安裝用戶端程式的電腦中,只要有支援JAVA瀏覽器,也可使用。

VNC Wiki:http://zh.wikipedia.org/zh-hk/VNC

2009年8月17日 星期一

SVG技巧:How to use SVG Include SVG

為方便做程式管理,「物件」是最理想的管理方式,但在Firefox的某些限制上,使用html + svg 的架構撰寫程式,在function取用上會產生function無法直接被取用的問題。但若是使用「SVG Include SVG」的方式,就不會產生資源取用上的難題。

google了數天,外文資源中實在找不到「SVG Include SVG」的教學,大部份都是「Html include SVG」,試著往xml的方向搜尋後,找到以下讀取外部xml檔案的程式碼法 :

function getDoc(){
 var XmlsReq;
 if(window.XMLHttpRequest){
  XmlsReq = new XMLHttpRequest();
 }else if(window.ActiveXObject){
  try{
   XmlsReq = new ActiveXObject("Msxml2.XMLHTTP");
  } catch(e){
   XmlsReq = new ActiveXObject("Microsoft.XMLHTTP");
  }
 }
 if(!XmlsReq) return;
 XmlsReq.open('GET','test.xml');
 XmlsReq.send(null);
 var xmldoc= XmlsReq.responseXML;
}

暫且不去理會我們所要讀取的xml檔案的內容,因為這裡的動作是要「讀取」外部的xml文件檔案,所以在執行前一定要確定路徑資料夾中已經建立必要的外資檔案。以上程式片段,最後宣告的xmldoc變數內容,即為同層資料夾之下所置放的「test.xml」。

接下來我們做一些小幅的修改:

var XmlsReq;

function getDoc(){
 if(window.XMLHttpRequest){
  XmlsReq = new XMLHttpRequest();
 }else if(window.ActiveXObject){
  try{
   XmlsReq = new ActiveXObject("Msxml2.XMLHTTP");
  } catch(e){
   XmlsReq = new ActiveXObject("Microsoft.XMLHTTP");
  }
 }
 if(!XmlsReq) return;
 XmlsReq.open('GET','test.svg');
 XmlsReq.send(null);
 setTimeout("getSVG()",10);
}

function getSVG(){
 var svgDoc= XmlsReq.responseXML;
}

以上程式片段,當然…如果取得的SVG內容將會被大量使用,svgDoc的宣告最好放到外部,但在這裡僅做簡單的教學。此時 svgDoc可以直接被當成一個SVG document使用,也就是說可以直接對這個變數做「getElementById」的動作。

2009年8月11日 星期二

Firefox修改:Firefox 介面修改(一)

前一篇文章已經知道Firefox介面內容及程式碼所在的檔案,本篇接著簡單的對Firefox的各工具做位置上的改變,以簡單的了解程式內容。

首先進行以下動作:
1、到Firefox資料夾下,進入 chrome資料夾,先找到「browser.jar」檔案
2、以任何可行的方式,將「browser.jar」壓縮檔開啟,但不必解壓縮,或是右鍵以7-Zip解壓軟體開啟


3、開啟壓縮檔後,進入 browser.jar\content\browser\ 之後,找到「browser.xul」檔案
4、將browser.xul從壓縮檔裡拉出來,建議先建立一個資料夾,再將browser.xul放到該資料夾,這個動作是準備對browser.xul做修改,我們無法從 browser.jar中修改此檔案,因而做這個動作。
5、開啟browser.xul(建議使用free ware : Notepad++ )。
開啟browser.xul檔案後,直接到行數第 733行,會看到 「<!--Menu-->」的字樣,可以確定以下開始的程式片段,會是Firefox的工具列至狀態列元件的所在位置。


a.接著在742及743行分別是 :

 <menu id="file-menu" label="&fileMenu.label;"
  accesskey="&fileMenu.accesskey;">

  其中 <menu>元件即為工具列中「File、Edit、View、…、Help」程式片段。

  

b.程式在744行為

  <menupopup id="menu_FilePopup" onpopupshowing="getContentAreaFrameCount』();">

  此為工具列下拉式選單中的「分隔線」元件

c.程式745到749行的內容

  <menuitem id="menu_newNavigator"
  label="&newNavigatorCmd.label;"
  accesskey="&newNavigatorCmd.accesskey;"
   key="key_newNavigator"
   command="cmd_newNavigator"/>

  其中『<menuitem>』即為工具列中,下拉式選單中的項目


  


6、到目前為止,對於工具列的元件已有初步的了解,接著回到742、743行看看…


  <menu id="file-menu" label="&fileMenu.label;"
  accesskey="&fileMenu.accesskey;">


  我們可以注意到「label="&fileMenu.label;"」這一段敘述中「&fileMenu.label」的地方,label屬性可以指定這個個按鈕項目顯示的文字,而「&fileMenu.label」可參照至其他檔案中的「fileMenu.label」所給定的數值。假如使用Notepade++編輯此xul檔案,可以將「fileMenu.label」做反白的動作,再按下ctrl + F,並指定搜尋所有解壓過的檔案,搜尋的檔案類型請設定為「*.js *.xml *.xul *.dtd」(以空白隔開搜尋值),設定好了之後按下「全找」:

  

在找到的資料中能夠發現在「en-US」資料夾中,browser目錄下browser.dtd檔案第137行有疑似指定fileMenu.label變數值的資料,雙擊載入此檔,程式會自動到達en-US中browser.dtd檔案的137行:

  

進入browser.dtd後,看到的137~139行的程式片段:

<!ENTITY fileMenu.label "File">
<!ENTITY fileMenu.accesskey "F">
<!ENTITY newNavigatorCmd.label "New Window">

我們可以試著將137行的 "File" 改成 "修改後"字樣,並且將下一行的 "F"改為 "修"。修改之後要注意的是「若要檢視修改的結果,一定要將修改過的檔案重新置入 *.jar中,重新開啟Firefox程式」,而將修改過的檔案置入 *.jar中的過程,Firefox是不能夠在開啟的狀態的,否則會無法取代檔案而失敗。以下是「修改後」工具列的結果:







對於其他按鈕顯示的文字,可以利用相同的方法去改變。


接著回到browser.xul檔案,注意以下行數:

  第722行到1415行:工具列程式碼
  第1417到1438行:瀏覽器頁面程式碼
  第1440到1436行:狀態列程式碼

這裡試著將各物件的位置做搬移的動作,首先請將第1417到1438行的程式碼做「剪下」的動作,剪下後,到722行的前一行做「貼上」的動作。

  


以上簡單介紹小幅修改Firefox介面的動作,下一篇對程式內容做其他方面的介紹。

2009年8月6日 星期四

Firefox修改:Firefox UI 及程式碼所在檔案 の 架構

本篇以介紹Firefox的使用者介面及Mozilla Firefox裡的Chrome資料夾內容為主,下一章節將介紹如何修改此UI。

一、原Firefox的介面配置如下:


由上至下分別是:
  • 標題列
  • 程式工具選項
  • 工具列
  • 頁面內容(browser content)
  • 狀態列

二、對於原Firefox介面,於Mozilla Firefox 資料夾裡,名為「Chrome」的資料夾裡,包涵了所有Firefox介面的程式內容:
  1. Chrome資料夾中的檔案主要分為兩種檔案類型:*.manifest、*.jar。
  2. *.manifest檔案:Chrome程式中,規定檔案讀取路徑的前置設定檔案。
  3. *.jar檔案:即一種壓縮檔,Firefox的介面內容主要存放在 *.jar內部。
  4. 相對於一個 *.jar 檔案,就會有一個搭配 *.jar的*.manifest檔案存在,例如 browser.jar必需搭配一個browser.manifest。
  5. 何謂Chrome? 請參考:https://developer.mozilla.org/en/Chrome_Registration,簡單的說,Chrome提供了一種簡易取用windows介面物件的機制,可供使用者建立視窗應用軟體。
三、 *.jar檔案包括:
  • browser.jar
  • en-US.jar
  • reporter.jar
  • toolkit.jar
  • pippki.jar
  • comm.jar
  • classic.jar
在修改Firefox的外觀當時,最重要的即是 browser.jar及en-US.jar兩個檔案。

四、browser.jar內容:
tools menu : 工具選項的內容,即File、Edit、…、Help這一群組的工具,由browser.jar配置。
tools : 在工具選項下方,「上一下」、「下一頁」等小工具,亦由browser.jar來建立。
browserContent : 即一般來說的「網頁頁面」,為網頁內容顯示區域,其定義於browser.jar內。
status bar : 位於整個程式最下方,同於IE的狀態列。

以上簡單介紹Firefox介面的架構及程式內容所在的檔案,後面一個章節將說明如何去做「修改」。

2009年8月4日 星期二

Firefox修改:How to re-build Firefox(XP環境)


這裡以Win XP作業系統做為Firefox的re-bulild及開發環境
1、首先確認re-build環境(這裡的環境指的即是電腦裡應該要有的某些套件)
  • 需有 Visual C++ (Visual Studio)
  • 下載 MozillaBuildSetup
  • Mozilla Build 程式碼原始檔 下載解壓至 C:\ 底下,檔案路徑需單純,不要有空白字元及某些不合法字元。(連結為FTP站,自選一個Firefox版本,建議下載3.5 rc3)

2、準備動作:

  • 將Mozilla解壓後,置於C:/下,並將資料夾名稱改為「mozilla」
  • 將先前下載好的 MozillaBuildeSetup 做setup的動作,程式路徑請設定於C:\mozillaBuilder。
  • 進入mozilla資料夾,建立一個「.mozconfig」檔案,並以對內容做編輯,加入以下兩行指令:

    ac_add_options --enable-application=browser

    mk_add_options MOZ_CO_PROJECT=browser

    加入指令的動作可參考下圖...

   
  • 以上動作完成後,進入MozillaBuilder資料夾,依據你的VS版本,選擇相對應的.bat檔案執行。
    start-msvc6.bat
    start-msvc71.bat  (VS 2003)
    start-msvc8.bat  (VS 2005)
    start-msvc9.bat   (VS 2008)

3、下達 firefox re-build 指令

假設系統內的VS為2008,即執行 start-msvc9.bat。一開始的畫面如下圖:

此時要做的動作是『進入mozilla資料夾』
 A、鍵入「cd c:」以到達C:\底下
 B、鍵入「ls」可以得知目前目錄下的所有檔案名稱
 C、鍵入「cd mozilla」進入 mozilla資料夾
最後鍵入「make -f client.mk build」,開始re-build Firefox
☆請注意:
 A、re-build的時間通常非常的漫長,也許數小時以上不等,主要視硬體狀況。
 B、re-build結束後,可以在 mozilla/dist/bin/ 找到 re-build完成的Firefox程式內容,執行Firefox.exe即可開啟re-build過的Firefox。
4、建立Install檔案:
 A、同第3步驟的前段,開啟.bat檔案後,將位置移至mozilla資料夾
 B、鍵入「make installer」,程式開始建立一個installer的執行檔
 C、到 C:\mozilla\dist\install\sea\ 之下即可找到剛剛建立完成的 .exe 檔案

新開張

測試用...