• Thứ Tư, 14/07/2010 08:11 (GMT+7)

    Trả lời thư bạn đọc

    BBT
    Mục giải đáp thắc mắc của bạn đọc do TS. Nguyễn Văn Hiệp phụ trách.

    Q: Xin hỏi code Visual Basic 6 lấy ma trận các điểm pixel của một ký tự với một font bất kỳ (kích thước font có thể thay đổi).

    A: Để lấy được ma trận các điểm pixel miêu tả một ký tự của một font bất kỳ, bạn có thể gọi 2 hàm API Windows sau đây:

    - CreateFontIndirect(): hàm này sẽ tạo 1 đối tượng font với tên, co chữ và các thuộc tính theo yêu cầu của bạn.

    - GetGlyphOutline(): hàm này trả về ma trận pixel của ký tự thuộc font chữ xác định.

    Sau đây chúng tôi xin giới thiệu qui trình điển hình để xây dựng ứng dụng VB 6.0 demo việc lấy ma trận pixel biểu diễn ký tự thuộc font chữ do người dùng yêu cầu rồi hiển thị ma trận pixel lên màn hình để người dùng xem:

    1. Chạy VB 6.0, tạo Project ứng dụng dạng "Standard EXE" đơn giản.

    2. Thiết kế Form gồm 3 textbox và 1 button như sau:

    3. Đặt tên cho 3 textbox lần lượt là txtFontName, txtSize, txtCode, tên của button là btnDisplay.

    4. Ấn kép chuột vào button Display để tạo thủ tục xử lý sự kiện Click chuột trên button. Khi cửa sổ soạn mã nguồn cho form hiển thị, hãy viết code VB 6.0 như sau:

    Option Explicit
    'Định nghĩa các kiểu cần dùng
    Private Type LOGFONT
    lfHeight As Long
    lfWidth As Long
    lfEscapement As Long
    lfOrientation As Long
    lfWeight As Long
    lfItalic As Byte
    lfUnderline As Byte
    lfStrikeOut As Byte
    lfCharSet As Byte
    lfOutPrecision As Byte
    lfClipPrecision As Byte
    lfQuality As Byte
    lfPitchAndFamily As Byte
    lfFaceName As String * 32
    End Type

    Private Type FIXED
    fract As Integer
    value As Integer
    End Type

    Private Type POINT
    x As Long
    y As Long
    End Type

    Private Type MAT2
    eM11 As FIXED
    eM12 As FIXED
    eM21 As FIXED
    eM22 As FIXED
    End Type

    Private Type GLYPHMETRICS
    gmBlackBoxX As Long
    gmBlackBoxY As Long
    gmptGlyphOrigin As POINT
    gmCellIncX As Integer
    gmCellIncY As Integer
    End Type

    'Định nghĩa các hằng gợi nhớ cần dùng
    Const GGO_BITMAP = 1
    Const XS = 20
    Const YS = 120

    'Khai báo các hàm API cần dùng
    Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long
    Private Declare Function CreateFontIndirect Lib "gdi32" Alias "CreateFontIndirectA" (lpLogFont As LOGFONT) As Long
    Private Declare Function GetGlyphOutline Lib "gdi32" Alias "GetGlyphOutlineA" (ByVal hdc As Long, ByVal uChar As Long, ByVal fuFormat As Long, lpgm As GLYPHMETRICS, ByVal cbBuffer As Long, lpBuffer As Any, lpmat2 As MAT2) As Long

    'Định nghĩa các biến cần dùng
    Dim lf As LOGFONT
    Dim buffer(5000) As Byte
    Dim buffersize As Long
    Dim gm As GLYPHMETRICS
    Dim m2 As MAT2

    'thủ tục xử lý Click chuột trên button Display
    Private Sub btnDisplay_Click()
    'Định nghĩa các biến cần dùng
    Dim prevFont As Long, hFont As Long, ret As Long
    Dim rows As Integer, r As Integer
    Dim cols As Integer, c As Integer
    Dim idx As Integer, mask As Integer
    Dim byt As Integer, binr As Integer
    'thiết lập các thuộc tính về font cần dùng
    lf.lfHeight = (CInt(txtSize.Text) * -20) / Screen.TwipsPerPixelY
    lf.lfWidth = 0
    lf.lfEscapement = 0
    lf.lfOrientation = 0
    lf.lfWeight = 300
    lf.lfItalic = False
    lf.lfUnderline = False
    lf.lfStrikeOut = False
    lf.lfFaceName = txtFontName.Text & Chr$(0)
    'tạo font chữ theo yêu cầu
    hFont = CreateFontIndirect(lf)
    If hFont = Null Then Exit Sub
    prevFont = SelectObject(Me.hdc, hFont)
    'thiết lập các ma trận chuyển đổi
    m2.eM11.value = 1: m2.eM11.fract = 0
    m2.eM22.value = 1: m2.eM22.fract = 0
    'tìm kích thước ma trận pixel ký tự
    buffersize = GetGlyphOutline(Me.hdc, CInt(txtCode.Text), GGO_BITMAP, gm, 0, 0, m2)
    If buffersize <= 0 Then Exit Sub
    'đọc ma trận pixel ký tự
    ret = GetGlyphOutline(Me.hdc, CInt(txtCode.Text), GGO_BITMAP, gm, buffersize, buffer(0), m2)
    'xác định số hàng, cột của ma trận
    rows = gm.gmBlackBoxY
    cols = gm.gmBlackBoxX
    'xác định số byte chứa các pixel của 1 cột ma trận
    binr = buffersize \ rows
    'xóa vùng hiển thị ma trận
    Me.ScaleMode = vbPixels
    Me.FillStyle = vbFSSolid
    Me.FillColor = Me.BackColor
    Me.DrawStyle = vbInvisible
    Me.Line (0, YS)-(Me.ScaleWidth, Me.ScaleHeight), , B
    'xác định màu vẽ các pixel
    Me.FillColor = RGB(0, 0, 0)
    'lặp hiển thị từng hàng pixel của ma trận
    For r = 0 To rows - 1
    idx = 1: byt = buffer(r * 4)
    mask = &H80
    'lặp hiển thị từng pixel trong hàng r
    For c = 0 To cols - 1
    If byt And mask Then dispbit r, c
    mask = mask \ 2
    If mask = 0 Then
    byt = buffer(r * binr + idx)
    idx = idx + 1
    mask = &H80
    End If
    Next
    Next
    End Sub

    'thủ tục vẽ 1 pixel được phóng to 8*8
    Private Sub dispbit(r As Integer, c As Integer)
    Dim x As Integer
    Dim y As Integer
    'xác định tọa độ của pixel
    x = XS + c * 8: y = YS + r * 8
    Me.Line (x, y)-(x + 7, y + 7), , B
    End Sub
     

    5. Chọn menu Run.Start để dịch và chạy thử ứng dụng. Khi form ứng dụng hiển thị, bạn thử nhập tên font, co chữ, mã ký tự cần xem rồi click chuột vào button Display để xem ma trận bitmap của ký tự tương ứng. Bạn thử hiệu chỉnh nội dung các textbox rồi click vào button Display để xem ký tự khác. Lưu ý phải cẩn thận nhập tên font đúng.

    Q: Xin chỉ giúp cho code ASP lấy dữ liệu từ csdl SQL.

    A: Trong trang ASP bạn có thể dùng các đối tượng ADO như Connection, Recordset,... để truy xuất dữ liệu trong database SQL (hay của database server bất kỳ). Thí dụ file DataDisp.asp sau đây sẽ truy xuất và hiển thị các record dữ liệu của bảng dữ liệu tên là "danhbadienthoai" (gồm 3 field tenthuebao, sodienthoai, diachi) nằm trong database "mydatabase" được quản lý bởi SQL Server chạy ở địa chỉ "HIEPCOMP\SQLEXPRESS". Tên và password của account được phép truy xuất database này là "sa" và "luonghoa":

    <%@ Language="VBScript" CodePage="65001"%>
    <HTML>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <HEAD>
    <%
    Sub DataDisp()
    'khai báo các biến cần dùng
    'Dim Connection1 As ADODB.Connection
    'Dim rs As ADODB.Recordset
    'Dim MyConString As String
    'thiết lập chuỗi ConnectionString chứa các tham số về database
    MyConString = "Provider=SQLOLEDB; Persist Security Info=False; SERVER=HIEPCOMP\SQLEXPRESS; UID=sa; PWD=luonghoa; Initial Catalog=mydatabase; Port=1433"
    'Tạo connection tới database
    Set Connection1 = Server.CreateObject("ADODB.Connection")
    Connection1.Open MyConString
    'tạo 1 đối tượng Recordset
    Set rs = Server.CreateObject("ADODB.Recordset")
    With rs
    Set .ActiveConnection = Connection1
    'thiết lập lệnh truy vấn động theo yêu cầu
    .Source = "SELECT * FROM danhbadienthoai"
    .Open
    End With
    'hiển thị kết quả lên các textbox tương ứng
    i = 1
    If Not rs.EOF Then
    'tao table va xuat hang dau tien
    Response.Write "<table border=1 cellPading=1 cellSpacing=1>" & vbCrlf
    Response.Write "<tr><th>Số thứ tự</th><th>Tên thuê bao</th><th>Số điện thoại</th><th>Điạ chỉ</th></tr>" & vbCrlf
    while Not rs.EOF
    stentbao = rs.Fields("tenthuebao")
    ssodthoai = rs.Fields("sodienthoai")
    sdiachi = rs.Fields("diachi")
    Response.Write "<tr><td>" & i & "</td><td>" & stentbao & "</td><td>" & ssodthoai & "</td><td>" & sdiachi & "</td><tr>" & vbCrlf
    i = i+1
    rs.MoveNext
    wend
    Response.Write "</table><p></p>" & vbCrlf
    Else
    Response.Write "<p>Không có record nào trong bảng dữ liệu của bạn cả!!<br>" & vbCrlf
    End If
    'đóng các đối tượng đã dùng
    rs.Close
    Connection1.Close
    Set rs = Nothing
    Set Connection1 = Nothing
    End Sub
    %>
    </HEAD>
    <BODY>
    Nội dung hiện hành của bảng danhbadienthoai là :
    <% DataDisp %>
    </BODY>
    </HTML>

    Còn nếu lập trình bằng ASP .Net, bạn có thể dùng các đối tượng sqlConnection, sqlCommand, sqlDataReader,... trong Package System.Data.SqlClient. Sau đây là qui trình điển hình để xây dựng trang ASP .Net có chức năng tương tự như trang DataDisp.asp trên đây:

    1. Chạy tiện ích quản lý database SQL Server (SQL Server Management Studio Express), tạo mới database có tên là mydatabase, trong database này bạn tạo 1 bảng dữ liệu có tên là danhbadienthoai, mỗi record gồm 3 field thông tin: tenthuebao, sodienthoai, diachi đều thuộc kiểu dữ liệu ntext (chuỗi Unicode). Cố gắng thêm 1 số record dữ liệu chứa nội dung thử nghiệm vào bảng danhbadienthoai.

    2. chạy Microsoft Visual Studio 200x. Chọn menu File.New Website để hiển thị cửa sổ "New Web site", chọn template "ASP .Net Website", chọn/nhập đường dẫn thư mục chứa Project Website, chọn ngôn ngữ lập trình là VB .Net rồi click button OK để tạo Project mới.

    3. Khi trang ASP .Net mặc định có tên là Default.aspx hiển thị (hoàn toàn trống), bạn hãy vẽ 1 button, đặt tên cho button này là btnDisp.

    4. Ấn kép chuột vào button btnDisp để tạo thủ tục xử lý Click chuột trên button này rồi viết code truy xuất từ bảng dữ liệu và hiển thị lên trang web:

    'thêm lệnh Imports sau vào đầu file để sử dụng các đối tượng SqlClient
    Imports System.Data.SqlClient

    Partial Class _Default
    Inherits System.Web.UI.Page
    //thủ tục xử lý chuột trên button
    Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
    'định nghĩa các biến cần dùng
    Dim myConnection As SqlConnection
    Dim MyConString As String
    'thiết lập chuỗi ConnectionString chứa các tham số về database
    MyConString = "server=HIEPCOMP\SQLEXPRESS;user id=sa; pwd=luonghoa; database=mydatabase;"
    'Tạo connection tới database
    myConnection = New SqlConnection(MyConString)
    myConnection.Open()
    'tạo 1 đối tượng Command thực hiện lệnh truy vấn
    Dim myCommand As New SqlCommand("SELECT * FROM danhbadienthoai", myConnection)
    Dim myReader As SqlDataReader
    myReader = myCommand.ExecuteReader()
    'hiển thị kết quả lên trang Web hiện hành
    If myReader.Read() Then
    'nếu có dữ liệu thì hiển thị dạng bảng
    Dim nItem As Integer = 1
    Dim tentbao As String
    Dim sodthoai As String
    Dim diachi As String
    'xuất tag miêu tả bảng và hàng header của bảng
    Response.Write("<table border=1>" & vbCrLf)
    Response.Write("<tr><th>Số thứ tự</th><th>Tên thuê bao</th><th>Số điện thoại</th><th>Địa chỉ</th></tr>" & vbCrLf)
    tentbao = myReader.GetString(0)
    sodthoai = myReader.GetString(1)
    diachi = myReader.GetString(2)
    'xuất hàng dữ liệu đầu tiên
    Response.Write("<tr><td>" & nItem & "</td><td>" & tentbao & "</td><td>" & sodthoai & "</td><td>" & diachi & "</td></tr>" & vbCrLf)
    nItem = nItem + 1
    'lặp xuất các record dữ liệuc còn lại
    While myReader.Read()
    tentbao = myReader.GetString(0)
    sodthoai = myReader.GetString(1)
    diachi = myReader.GetString(2)
    Response.Write("<tr><td>" & nItem & "</td><td>" & tentbao & "</td><td>" & sodthoai & "</td><td>" & diachi & "</td></tr>" & vbCrLf)
    nItem = nItem + 1
    End While
    'xuất tag kết thúc bảng
    Response.Write("</table>" & vbCrLf)
    Else
    'nếu không có dữ liệu thì báo lỗi
    Response.Write("<P>Bảng dữ liệu chưa có nội dung!</P>")
    End If
    'đóng các đối tượng đã dùng lại
    myReader.Close()
    myConnection.Close()
    End Sub
    End Class

    5. Chọn menu Debug.Start Debugging để chạy thử trang ASP .Net vừa xây dựng. Khi trang web hiển thị, hãy nhấn chuột vào button để trang web truy xuất database và hiển thị kết quả truy xuất được.

    Tôi là kỹ sư chuyên ngành cơ điện, thực hiện đề tài "Mô phỏng Bàn điều khiển thiết bị tua bin khí" trên bàn điều khiển có đồng hồ đo các thông số của thiết bị Tua bin khí (kiểu như động cơ máy bay). Đồng hồ này gồm có 3 kim để đo 3 thông số khác nhau, tôi sử dụng 1 Form với thuộc tính BackgroundImage là mặt đồng hồ, Panel 1 cũng có BackgroundImage là kim đồng hồ thứ nhất, PictureBox là kim đồng hồ thứ 2 thì không vấn đề gì nhưng còn kim thứ 3 thì nếu sử dụng tiếp Panel 2 thì khi nạp lên đồng hồ cứ nháy liên tục trông rất xấu, còn sử dụng PictureBox thứ 2 thì PictureBox thứ nhất không nhìn thấy gì mà chỉ thấy Panel 1. 

    Q: Xin hỏi code ANSI C nhận diện card màn hình, mouse, keyboard, đọc/ghi và format đĩa.
    Code chạy không cần hệ điều hành, nói rõ hơn là máy mới ráp chưa cài bất kỳ hệ điều hành nào.

    A: Tùy theo yêu cầu người dùng, họ sẽ gắn vào máy nhiều thiết bị I/O (nhập xuất) khác nhau. Ngay cả 1 thiết bị I/O cụ thể (thí dụ như card màn hình) cũng có nhiều hãng chế tạo khác nhau, mỗi hãng chế tạo nhiều thế hệ (model) card (thiết bị I/O) khác nhau. Do đó viết chương trình nhận diện và điều khiển trực tiếp thiết bị I/O bởi người dùng là không nên làm vì nếu có viết được, chương trình sẽ phụ thuộc hoàn toàn với 1 thiết bị cụ thể, như thế khi thay thế thiết bị khác (chắc chắn sẽ xảy ra), chương trình cũ sẽ lỗi thời và không hoạt động được nữa.

    Để giải quyết vấn đề trên, hãng nào lắp máy tính, hãng đó sẽ phải viết module phần mềm quản lý trực tiếp các thiết bị phần cứng trên máy mình. Module này trên máy PC được gọi là BIOS (Basic Input/Output System) và được ghi trong ROM của máy đó (ta gọi là ROM BIOS). BIOS chứa nhiều hàm chức năng, mỗi hàm thường được kích hoạt bằng cơ chế ngắt quảng (interrupt) và sẽ quản lý 1 thiết bị I/O cụ thể. Thí dụ ngắt 13h phục vụ việc quản lý các thiết bị chứa tin như đĩa cứng, đĩa mềm,... Ngắt 10h phục vụ quản lý card màn hình. BIOS còn chứa trình boot máy, trình này làm nhiều công việc trên nhiều bước. Thí dụ bước đầu tiên là nhận diện và kiểm tra sơ bộ các thiết bị thiết yếu nhất có hoạt động tốt không như CPU, bộ nhớ RAM, bàn phím, màn hình,...

    Hệ điều hành MSDOS/Windows/Linux cũng không truy xuất trực tiếp phần cứng của máy, chúng chỉ truy xuất thiết bị thông qua dịch vụ của BIOS hay của module device driver đi kèm theo thiết bị. Còn chương trình ứng dụng thì truy xuất phần cứng thông qua dịch vụ của hệ điều hành để code của ứng dụng độc lập hoàn toàn với phần cứng cấp thấp và nhờ vậy, khi thay đổi phần cứng thì phần mềm ứng dụng tiếp tục chạy tốt chứ không cần phần hiệu chỉnh gì cả.

    Tóm lại, nếu chưa có yêu cầu đặc biệt gì, bạn nên đọc chương trình mã máy trong ROM BIOS để biết cách thức cụ thể về việc nhận diện và truy xuất từng thiết bị I/O của máy. Còn nếu bạn là người tự thiết kế và chế tạo máy tính mới, bạn phải biết máy của mình dùng các thiết bị nào, mỗi thiết bị có tính chất vật lý cụ thể nào, từ đó bạn viết các đoạn chương trình nhận diện và truy xuất các thiết bị đó. Tuy nhiên để làm tốt cả 2 công việc: thiết kế chế tạo phần cứng, viết phần mềm truy xuất các thiết bị do tự mình lắp đặt, bạn cần học hỏi để trang bị cho mình nhiều kiến thức chi tiết về phần cứng và lập trình, các kiến thức mà bạn cần trang bị tương đương với kiến thức được trang bị cho 1 sinh viên kỹ sư công nghệ thông tin thuộc ngành kỹ thuật máy tính của một vài trường đại học ở Việt Nam, còn hầu hết các sinh viên ngành công nghệ thông tin khác đều chỉ được trang bị chủ yếu kiến thức lập trình ở cấp ứng dụng.

    Q: Xin chỉ cách xây dựng ứng dụng chuyển đổi qua lại giữa các tập tin *.dat, *.flv, *.avi,... bằng ngôn ngữ VB 6.0.

    A: Định dạng của các file video như *.dat, *.flv, *.avi là rất phức tạp, những người không chuyên rất khó hiểu nổi, vì vậy khó mà viết được ứng dụng chuyển đổi giữa các định dạng file video này. Nếu bạn muốn thử sức mình, trước hết bạn hãy vào Internet, tìm đọc thử một vài tài liệu về định dạng ảnh nào đó (thí dụ *.dat), nếu không hiểu thì bạn nên dừng lại rồi tìm và dùng các ứng dụng đã có sẵn giúp bạn chuyển đổi giữa các định dạng file video – hiện có nhiều ứng dụng như vậy.


    ID: A1006_132