GSI

타이머 사용하기

WPF 2007. 9. 10. 23:15 |

본 글은 http://www.hoons.kr 에 있는 내용을 나름대로 이해되는 부분에 한해서 적은 것입니다.

타이머 사용을 위해서 네임 스페이스를 하나 선언합니다.
using System.Windows.Threading;

타이머 변수를 하나 선언합니다.
DispatcherTimer dt = new DispatcherTimer();

그리고 난수를 하나 생성하게 됩니다.
Random ran = new Random();

이후에 코드에 맞는 해당 값들의 전역 변수들을 선언 하면 됩니다.

dt의 타이머를 사용하기 위해서 초기 설정을 하게 됩니다.
dt.Interval = TimeSpan.FromMilliseconds(30);
dt.Tick += new EventHandler(dt_Tick);
dt.Start();


Tick에 추가한 이벤트 핸들러에 대한 함수 원형을 추가 합니다.
void dt_Tick(object sender, EventArgs e)
{
   .....
}


..... 이상 코드는 여기까지.......

Start()를 하고 나면 계속해서 타이머가 동작 하게 됩니다.
타이머 동작을 멈추고 싶다면 dt.Stop()를 해주면 됩니다.


이후에 참고할 만한 코드는

* 랜덤 함수는 ran.NextDouble() 를 사용해서 double형 값을 가져 올수 있습니다.
   물론 double 말고도 int형을 가져 오는 함수도 존재 합니다.
* Canvas에 있는 오브젝트의 위치를 변경하기 위해서 아래와 같은 코드가 가능해 집니다.
   Canvas.SetLeft(im, currX);
   Canvas.SetTop(im, currY);
   - im은 Canvas에 있는 객체의 Name 이며, currX, currY 는 전역 변수로 가지고 있는
     위치가 되겠습니다.
* 해당 값의 절대값을 사용하기 위해서 아래의 코드를 사용합니다.
    if (Math.Abs(currX - destX) < 1)
    {
        destX = ran.NextDouble() * this.ActualWidth;
        destY = ran.NextDouble() * this.ActualHeight;
    }




Posted by gsi
:

Blend의 튜토리얼 중에 ColorSwitch 라는 예제가 있다.
그곳에서 보면 칼라 스위치는 마우스가 Enter 되면 앞쪽으로 나오게 된다.
이 부분은 SetZIndex 가 담당하게 되는데.
조작 하는 방법이 조금은 다르다.

Blend에서 Grid 내부에 Canvas를 3개를 겹치게 배치 했다가 가정하겠다.
여기서 우리는 원하는 Canvas를 제일 위쪽에 가져다 놓기를 바랄때가 있을것이다.
이때 사용하는게 SetZIndex를 사용하면 된다.

하지만 이것은 Name를 가지는 객체에 포함되어져 있는 함수는 아니기 때문에 아래의
코드를 이용해야 한다.

관련msdn 로컬 주소 : http://msdn2.microsoft.com/en-us/library/system.windows.controls.panel.zindex.aspx

Canvas.SetZIndex(Step0, 1);

위와 같은 코드를 사용할 수 있다.
Canvas를 객체의 SetZIndex를 변경해준다고 생각하면 되며,
Grid 내부에 Canvas가 여러개 있을때 사용하게 되는 것이다.
즉, Grid 내부의 Canvas를 이동시키고자 할때는

Canvas.SetZIndex()를 사용하면 되는 것이다.

Step0이라는 것은 Blend에서 Canvas의 이름을 의미한다.

그리도 뒤에 오는 1이라는 숫자는
Blend에서 여러개의 객체를 배치 하고 나서 ZIndex를 보면 모두 0인 것을
알수 있다. 이 경우에 0 이지만 배치된 순서대로 화면에 표현되도록 되어 있다.
그래서 1이라는 숫자는 최상단에 배치 한다고 생각 하면된다.

다른 방법으로 3개의 객체가 있다고 했을때 0 ~ 2까지 3개의 ZIndex를
사용해도 된다.

간단하게 하기 위해서는 모두 0이고 최상단에 올려질것만 1로 설정하면
편하게 할 수 있을거 같다.

Posted by gsi
:

버튼 위치 이동시키기.

WPF 2007. 9. 9. 05:39 |

Button을 이동시키기 위해서는 Margin의 값을 잘 살펴 보면 된다.
이 값이 어떤 Property이고 어떻게 이동해 주어야 하는지 찾아야 한다.

참고로 Button의 Name가 MoveObject 라고 가정하고 시작한다.

Blend에서 Button을 하나 생성한 후에 마우스로 이동해 보자.
그러면 Margin의 값이 바뀌는 것을 알수 있다. 즉 Left, Top의 값이 바뀌게 되는 것이다.
그렇다면 비아인드 코드를 작성 할려면 Margin에 특정 값을 넣어 주면 되는 것이다.

MoveObject.Margin.Left 라는 속성이 있지만 이것은 특정 int, double의 값을 추가할수는 없다.

그래서 cs 파일의 MoveObject.Margin의 툴팁 정보를 보니
FrameworkElement.margin property 라고 나오는 것을 볼 수 있었다.
그래서 msdn에서 FrameworkElement.margin을 찾아 보았다.

아하! Syntax 에 보니
C#
public Thickness Margin { get; set; }
이런 구문을 볼 수 있었다. 바로 Thickness를 하나 생성한 후에 값을 추가 하고
Margin에 대입해 주면 되는거라고 짐작이 될것이다.

그래서 아래와 같은 코드를 사용해서 하면 된다.

Thickness th = new Thickness(marginleft, margintop, 0, 0);
MoveObject.Margin = th;
이상.  (msdn을 잘 활용하자. 거의 모든 코드가 다 있다. ^^)
Posted by gsi
:

랜덤 코드 사용하기

WPF 2007. 9. 9. 05:34 |

네임스페이스 선언 : using System.Threading;

코드 사용방법 :

Random autoRand = new Random();
double marginleft = autoRand.NextDouble() * (this.Width - MoveObject.Width);
double margintop = autoRand.NextDouble() * (this.Height - MoveObject.Height);

Thickness th = new Thickness(marginleft, margintop, 0, 0);
MoveObject.Margin = th;

Next()는 int형 정보를 가져올때 사용한다.
NextDouble()는 double형 정보를 가져 올때 사용한다.

이후에도 seed의 값을 입력 하는 방법도 있으니 참고 하기 바란다.

Posted by gsi
:

UIElement3D extensibility - 3D Video Carousel

Recently I've been working on a screencast, which goes over some advanced aspects of working with Element3D. In the meantime, this sample demonstrates WPF's Orcas Beta 2 UIElement 3D technology, covering the essentials for how you can make your own reusable UIElement3D controls for 3D. I have two in here:

  1. A "KeepCaseUIElement3D", a representation of a real world DVD case, with the added twist of playing video on the inside. It's API consumes Uri's for cover images and a media source, rather than traditional models, meshes, and materials in 3D .
  2. A "MovieCarousel" - a simple 3D carousel layout control which re-orients itself to position the object which was last clicked towards the user.

You will need to operate with the WPF V3.5(Orcas) Beta 2 Bits. You can get the Visual Studio Orcas Beta 2 installation with WPF from here.

A set of streaming WPF tutorial Videos

Concepts you can see in practice with this sample include:

  • Creating interactive 3D controls as interactive containers on non-interactive 3D models (Hint - Leverage existing 3D Xaml with little effort)
  • Creating a Custom Visual3D container type
  • Use of StaticResources from Application.Resources to separate mesh details from overall structure
  • Databinding a mesh texture to consume a local DP exposed as a URI, via a data binding type converter
  • 3D Layout - Cylinder Layout Helper class
  • Playing Video as a material on 3D

If you have any questions on the details of this sample, feel free to send me a message, or leave a relevant comment- odds are fair other folks have similar questions, which could make for interesting future blog postings!

 Thanks!

관련자료 : http://blogs.msdn.com/pantal/archive/2007/08/22/uielement3d-extensibility-dvd-keep-case-player-cylindrical-carousel-layout.aspx

Posted by gsi
:

What’s new in WPF 3.5

WPF 2007. 9. 7. 09:29 |

What’s new in WPF 3.5

With the release of WPF 3.5 beta 2 (download here: http://www.microsoft.com/downloads/details.aspx?FamilyId=D2F74873-C796-4E60-91C8-F0EF809B09EE&displaylang=en), we’ve added some exciting new features to WPF 3D.  At a very high level these can be grouped in to two main additions: UIElement3D and Viewport2DVisual3D.  Over the next couple of weeks we’ll be adding examples and tips and tricks to the blog on these new additions, but for now we’ll start with a quick overview of what both of these provide.

UIElement3D

In the 2D world, UIElement adds layout, input, focus and eventing on to Visual.  UIElement3D brings these same things (except no layout) to 3D.  What this means is that the standard events and means of adding event handlers that you’re used to with UIElements now applies in the 3D world with UIElement3D. 

UIElement3D itself is an abstract class that derives from Visual3D.  To make it useable out of the box without having to derive from UIElement3D yourself, we’ve provided two new classes:  ModelUIElement3D and ContainerUIElement3D. 

ContainerUIElement3D does exactly what its name says.  It is a container for other Visual3Ds.  It has one main property, Children, which is used to add and remove 3D children.  The ContainerUIElement3D doesn’t have a visual representation itself, but rather is just a collection of other 3D objects.

ModelUIElement3D has one property, Model, which is the Model3D that should be displayed to represent the UIElement3D.  It has no children itself, and in some ways you can think of ModelUIElement3D like a Shape in the 2D world.

If you’re familiar with ModelVisual3D, then ContainerUIElement3D and ModelUIElement3D should look very familiar.  The difference is we’ve gone and split the functionality of ModelVisual3D (i.e. a model and children) in to two separate classes, one with a model and the other with children.

With these then, making use of layout, focus and eventing is very easy.  For instance, say you want to create a 3D object that responds to mouse events, you can just do:

                <ModelUIElement3D  MouseDown="OnMouseDown"/>

And then in the code behind have:

      protected void OnMouseDown(object sender, MouseButtonEventArgs e)

      {

          Console.WriteLine("Hello");

      }

If you have experience adding event handlers in the 2D world, then this should look immediately familiar.  In fact it’s exactly the same, and UIElement3D is going to handle the same routed events that a UIElement deals with.  With the addition of UIElement3D you now get all the great functionality that UIElement provided to 2D, but now in the 3D world!

Viewport2DVisual3D

The second main addition is Viewport2DVisual3D which enables you to put interactive 2D on 3D in WPF.  If you’ve used the 3DTools work that was released shortly after the 3.0 release of WPF, Viewport2DVisual3D will look very familiar to you.  With 3.5 though we’ve fully integrated 2D on 3D in to WPF rather than requiring a separate DLL to have this feature.  The 2D and 3D trees are also integrated now, so if you walk up to a 2D visual on 3D and ask it for its parent, it will tell you the 3D object it is on.

Viewport2DVisual3D derives from Visual3D and has three main dependency properties: Visual, Geometry and Material.

Visual – This is the 2D Visual that will be placed on the 3D object.

Geometry – The 3D geometry for the Viewport2DVisual3D

Material – This describes the look of the 3D object.  You can use any material you want.  For the material that you want to have the Visual be placed on, you simply need to set the Viewport2DVisual3D.IsVisualHostMaterial attached property to true.

Below is a XAML example using Viewport2DVisual3D

<Viewport2DVisual3D Geometry="{StaticResource plane}">

        <Viewport2DVisual3D.Material>

          <DiffuseMaterial  Viewport2DVisual3D.IsVisualHostMaterial="true" />

        </Viewport2DVisual3D.Material>

       

        <Button>3.5!</Button>          

      </Viewport2DVisual3D>

The above is a very quick overview of what is added in 3.5, so expect more posts on more specific details as well as some code samples on how to use it.

-Kurt Berglund

Posted by gsi
:

Of course I couldn't mention a technique of possible real-time cell-shading yesterday without actually trying it out. No, I didn't attempt to derive from BitmapEffect. (I'd love to take a crack at BitmapEffect but I simply cannot justify the expenditure of time.)

Instead, I tried the RenderTargetBitmap approach. Here's a rough outline:

  • Lay out your Page or Window normally but instead of defining a Viewport3D element, use a Border instead. The Border is perhaps the simplest FrameworkElement derivative that has a Background property. Give the Background property an object of type ImageBrush.
  • Whatever you would have put into your Viewport3D put into a Viewport3DVisual instead. Set the Viewport property of the Viewport3DVisual to the actual size of the Border element. You'll need a handler for the SizeChanged event of the Border to keep this Viewport property updated when the Border size changes.
  • In that same SizeChanged event handler for the Border, create an object of type RenderTargetBitmap the same size as the Border and the Viewport3DVisual. You'll be recreating this bitmap whenever the size of the Border changes.
  • Insteall event handlers for anything else (such as scrollbars) that affect the 3D scene defined within the Viewport3DVisual.
  • Whenever anything happens that affects the appearance of the Viewport3DVisual perform the following actions:
    • Clear the RenderTargetBitmap by calling the Clear method.
    • Render the Viewport3DVisual on the bitmap by calling the Render method.
    • Dump the pixel bits of the RenderTargetBitmap into an array by calling CopyPixels.
    • Do whatever processing you want on the pixel bits. (For cell-shading, I just AND-ed each 32-bit ARGB pixel with 0xFFC0C0C0.)
    • Create a new bitmap based on the altered pixel bits by calling BitmapSource.Create.
    • Set that new bitmap to the ImageSource property of the ImageBrush object set to the Background property of the Border.

Here's the RealTimeCellShading source code. Sorry I can't give you an XBAP, but apparently Clear and CopyPixels are prohibited methods for partial trust. (But Render and BitmapSource.Create are mysteriously OK. Hey — I don't make up the XBAP rules!)

I've used an AmbientLight at 1/4 white and DirectionalLight of 3/4 white with a direction of (2, –3 –1). I've provided a pair of scrollbars to rotate the camera relative to the teapot, and a pair of sliders to rotate the teapot relative to the camera and light sources. Here's a view with the teapot slightly rotated:

Posted by gsi
:

사용자가 지정한 여러가지 정보들을 ListBox에 표현하는 방법을 기술합니다.
하나의 사용자 정보에는 여러개의 정보가 포함되어 있으며,
그 정보를 ObservableCollection 와 같은 Collection의 객체로 리스트화 합니다.

본 내용은 WPF Application을 기초로 합니다.

** 사용자 데이터 구성**

public class Place
{
    private string _name;

    private string _state;

    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }

    public string State
    {
        get { return _state; }
        set { _state = value; }
    }

    public Place(string name, string state)
    {
        this._name = name;
        this._state = state;
    }

    public override string ToString()
    {
        //return base.ToString();
        return _name.ToString();
    }
}

public class Places : ObservableCollection<Place>
{
    public Places()
    {
        Add(new Place("Bellevue", "WA"));
        Add(new Place("Gold Beach", "OR"));
        Add(new Place("Kirkland", "WA"));
        Add(new Place("Los Angeles", "CA"));
        Add(new Place("Portland", "ME"));
        Add(new Place("Portland", "OR"));
        Add(new Place("Redmond", "WA"));
        Add(new Place("San Diego", "CA"));
        Add(new Place("San Francisco", "CA"));
        Add(new Place("San Jose", "CA"));
        Add(new Place("Seattle", "WA"));
    }
}


**xaml에서 사용방법**
1. 네임 스페이스 추가
xmlns:c="clr-namespace:WpfApplication1"

2. Window.Resources에 클래스 등록
<Window.Resources>
        <c:Places x:Key="PlacesData" />
        ................
</Window.Resources>


3. 화면 구성
<StackPanel>
      <TextBlock FontSize="18" Margin="5" FontWeight="Bold"
                 HorizontalAlignment="Center">Data Trigger Sample</TextBlock>
      <ListBox Width="180" HorizontalAlignment="Center" Background="Honeydew"
                 ItemsSource="{Binding Source={StaticResource PlacesData}}"/>
</StackPanel>


아래와 같은 화면으로 구성이 됩니다.

사용자 삽입 이미지


위의 내용들을 보시면 하나같이 WpfApplication1.Place 라고 나옵니다.
이것은 Collection 내부에 있는 오브젝트의 값을 ToString를 통해서 기본 값을 가져 오기 때문인데요(말이 좀 그렇다^^) 여기서 ToString()를 오버라이트 해서 _name의 값을 리턴 하도록 해보겠습니다.

Place 클래스 내부에 ToString()를 추가합니다.
public override string ToString()
{
     return base.ToString();
}

추가를 하게 되면 위와 같은 코드가 자동으로 추가가 됩니다.

여기서 return base.ToString()return _name.ToString()로 바꾸어 주면
위의 내용이 아니라 이름으로된 결과물을 보실수 있을겁니다.

이후에는 Place에 있는 정보들을 다 보여 주는 템플릿을 구성할 수 있습니다. ^^

본 예제는 msdn 로컬 파일주소를 참조 하세요.
ms-help://MS.MSDNQTR.v90.en/wpf_conceptual/html/0f4d9f8c-0230-4013-bd7b-e8e7fed01b4a.htm
(물론 웹에도 같은게 있습니다. 주소는 직접 찾기 바랍니다. ^^..)
Posted by gsi
:

본 내용은 msdn에 있는
How to: Control When the TextBox Text Updates the Sources 에 대한 내용을
조금 나름대로 이해 할 수 있도록 정리한 것입니다.
영어는 잘 몰라서 번역 수준은 아닙니다.


TextBox의 Text는 기본적으로 UpdateSourceTrigger 의 값이 LostFocus로 되어 있다고 합니다. 그래서 Text를 다 적고 나서 마우스나 기타 다른 것을 통해서 Focus가 다른 데로 갔을때 업데이트가 되도록 되어 있습니다.

하지만 이 것을 Text를 입력 하고 있는 중간에 계속 해서 업데이트가 가능하게 할려면
UpdateSourceTrigger를 수정해줘야 하는거 같습니다.

즉, TextBox 의 Binding 속성을 사용해서 UpdateSourceTrigger의 값을 PropertyChanged로 수정해주어야 되는거 같네요.

블렌드에서 TextBox와 TextBlock을 사용해서 값을 Data Binding 해서 테스트를 해보면
값이 바뀌는것을 볼 수 있습니다.

하지만 지금 예제는 cs 파일을 통해서 연동하는 부분을 살펴 보게 되겠습니다.

Person.cs 파일을 하나 생성하게 되는데요.

1. 네임 스페이스 지정
using System.ComponentModel;

2. INotifyPropertyChanged를 상속 받는 클래스 생성
class Person : INotifyPropertyChanged
{
}


3. 데이터 값으로 name를 생성
private string name;

4. PropertyChangedEventHandler 이벤트 핸들 생성
public event PropertyChangedEventHandler PropertyChanged;

5. name를 사용할 인터페이스(??)를 생성, get, set 두개 지정
public string PersonName
{
    get { return name; }
    set
    {
        name = value;

        OnPropertyChanged("PersonName");
    }
}


6. PropertyChanged 를 처리할 함수 생성
protected void OnPropertyChanged(string name)
{
    PropertyChangedEventHandler handler = PropertyChanged;
    if (handler != null)
    {
        handler(this, new PropertyChangedEventArgs(name));
    }
}

cs 파일을 만든 다음에 xaml을 처리 합니다.
1. Person.cs 파일을 사용하기 위해서 네임 스페이스를 지정
xmlns:src="clr-namespace:UntitledProject1"

2. Window.Resources 에 Person의 키를 생성
<src:Person x:Key="myDataSource" PersonName="Joe"/>
 - x:Key="myDataSource" 를 하게 되면 Person의 생성자가 호출되는거 같네요.
 - PersonName="Joe" 를 하게 되면 public string PersonName 의 set 함수가
호출되는거 같습니다.

3. TextBox의 Text 속성에 바인딩 시킵니다.
<TextBox.Text>
    <Binding Source="{StaticResource myDataSource}" Path="PersonName"
                   UpdateSourceTrigger="PropertyChanged"/>
</TextBox.Text>
 - Source에는 Window.Resource에 Person을 선언해 놓은 myDataSource를 적용합니다. Path에는 PersonName를 추가 하게 되는데요. PersonName는 Person.cs 파일에 존재 하는 것입니다. (만약 xml을 사용하게 된다면 Path가 아니라 XPath가 되며 "PersonName"이 아니라 @"PersonName"가 됩니다.)
 - UpdateSourceTrigger="PropertyChanged"를 셋팅해 주게 됩니다.

4. TextBlock 의 Text 속성에 바인딩 시킵니다.
<TextBlock Text="{Binding Source={StaticResource myDataSource}, Path=PersonName}"/>
 - UpdateSourceTrigger 는 지정하지 않고 TextBox와 동일하게 구성합니다.
 - 위의 코드는 아래와 같이도 쓸수 있겠네요.
<TextBlock>
    <TextBlock.Text>
        <Binding Source="{StaticResource myDataSource}" Path="PersonName"/>
    </TextBlock.Text>
</TextBlock>


-----------------------------------------------------
작동 흐름을 대충 찍어 보면..

1. <src:Person x:Key="myDataSource" PersonName="Joe"/>
여기를 거치게 되면서
- public Person() 생성자가 호출 됩니다.
- public string PersonName 의 set에 value로 "Joe"가 입력 됩니다.
- OnPropertyChanged("PersonName"); 가 호출됩니다.
- OnPropertyChanged 내부에서는 handler가 null 이라서 그냥 빠져 나가네요.

2. Path="PersonName"
- 이 구문을 만나게 되면서 public string PersonName 이 호출되고 여기에서 name의 값을 get으로 리턴 시켜 줍니다.

3. TextBox의 Text에 내용 입니다.
- public string PersonName 의 set 가 호출 됩니다.
- OnPropertyChanged("PersonName"); 를 호출합니다.
- OnPropertyChanged() 내부에서 handler가 null이 아니게 되며, handler()를 호출하게 됩니다.
- public string PersonName 가 호출 되게 되는데요.. 음 아무래도 여기서, xaml의 코드를 거쳐서 TextBlock의 Text의 값이 변하게 되는거 같습니다.

**이상 간단하게 봤습니다.**

WPF를 하면서 C#의 스킬 부족과 영어 울렁증, xaml의 코드 난해함에.. 많이 헤매게 되는거 같습니다. 빨리 익혀서 이것저것 만들어 보는 날이 왔으면 좋겠네요 ^^.

강좌가 조금 난잡해 진거 같은데요.. ^^..
본 강좌의 소스는 인터넷의 msdn 사이트나 msdn을 설치 하셨다면 아래 주소에 있습니다.^^
ms-help://MS.MSDNQTR.v90.en/wpf_samples/html/b2906631-8a4b-43b4-b077-9e732a8ff363.htm (로컬msdn)

잘못된 부분이나 조금 도움이 될만한 내용이 있으시다면 적어 주시면 고맙겠습니다. ^^

Posted by gsi
:

아래의 코드는 내가 정신없이 한줄을 작성하면서 생긴 일이다.
참으로 어이가 없는 경우이긴 하지만 발생할 수 있는 상태가 된 나로서는
아무래도 헤롱헤롱 하는 상태인듯 하다.

d:\NG_Project\Project\NGTools\NGMakerShop080\NGMakerShop080_Work\DataMgr\NGBObject.h(70): error C2039: 'first' : is not a member of 'std::_Tree<_Traits>::iterator'
        with
        [
            _Traits=std::_Tmap_traits<int,int,std::less<int>,std::allocator<std::pair<const int,int>>,false>
        ]

문제가된 코드

  map< int, int> m_test;
  m_test[10] = 10;
  map< int, int>::iterator iter = m_test.begin();
  int aaa = iter.first; //<--여기..

이 코드를 보고도 어디가 문제인지 모르는 분은 나랑 비슷한 상태인듯 하다 ^^

이 코드는 아래와 같이 되어야 한다.

int aaa = (*iter).first;

앞으로는 조금더 정신 차리고 해야 할거 같다.

Posted by gsi
:

stl string trim 구현하기

STL 2007. 9. 6. 14:43 |

string을 사용하고 있지만.. trim이 없는듯 합니다. -.- 혹시 알면 댓글.. 부탁 드림..

아래와 같은 프로그램 경로가 있다고 햇을때 프로그램 파일 부분만 잘라 낼려고 할대
아래와 같은 코드를 사용했습니다.

원본 패스 : d:\gsi_project\projectx\bin\AttachImageMakerd.exe
결과 패스 : d:\gsi_project\projectx\bin

//초기화

string appPath = argv[0];
string appdir;
appdir.clear();
//뒷 부분을 잘라 내야 하기 때문에 우선 뒤쪽에서 '\'를 찾는다.

int findidx = (int)appPath.rfind('\\');

//찾은 인덱스를 사용해서 잘라낸다.

appdir = string(appPath, 0, findidx); //appPath : 풀 패스, 0 : 시작인덱스, findidx : 끝 인덱스

이상...

Posted by gsi
:

float, int 등을 string 변환 - ostringstream 이용

#include <sstream>

std::ostringstream outstream;
outstream << 숫자등등
std::string str = outstream .str()

Posted by gsi
:

for_each()를 사용할때

//클래스

class Widget {
public:
 Widget(int var) : value(var) {}

 void Test() {
  cout << "값 " << value << endl;
 }

public:
 int value;
};

//함수 선언

void Test(Widget& w)
{
 cout << w.value << endl;
}

//사용하는곳

 vector<Widget> vw;

 vw.push_back(Widget(1));
 vw.push_back(Widget(2));
 vw.push_back(Widget(3));
 vw.push_back(Widget(4));
 vw.push_back(Widget(5));

//일반 함수는 Test 또는 ptr_fun(Test) 라고 하면 됩니다.

 for_each(vw.begin(), vw.end(), Test);
 for_each(vw.begin(), vw.end(), ptr_fun(Test));

//클래스 내부의 함수를 접근 할 때는 vw의 형태가 참조냐 포인터냐에 따라서

//달라 집니다. 참조 이기 때문에 mem_fun_ref(&Widget::Test)를 사용합니다.
 for_each(vw.begin(), vw.end(), mem_fun_ref(&Widget::Test));

 vector<Widget*> lpw;

 lpw.push_back(new Widget(1));
 lpw.push_back(new Widget(2));
 lpw.push_back(new Widget(3));
 lpw.push_back(new Widget(4));
 lpw.push_back(new Widget(5));

//포인터이기 때문에 mem_fun(&Widget::Test)를 사용하게 되지요.

 for_each(lpw.begin(), lpw.end(), mem_fun(&Widget::Test));

Posted by gsi
:

vector <> 에 포인터 객체를 넣게 되면 많은 부분 불편한게 생긴다.
메모리의 삭제에 있어서 다른 처리를 해야 하기 때문이다.

하지만 boost의 shared_ptr를 사용하면 아주 편하게 구현이 됩니다.
관련 내용 : http://crowmania.cafe24.com/crowmania/?p=50

[헤더]
#include <vector>
using namespace std;
#include <boost/shared_ptr.hpp>

//테스트할 클래스 구성
class CMemTest
{
public:
 CMemTest() : _val(0)
 {
 }
 CMemTest(int val)
 {
  _val = val;
 }
 ~CMemTest()
 {
 
 }

 int _val;
};

//부스터에 맞는 타입디파인
typedef boost::shared_ptr<CMemTest> SPMemTest;

[코드]
vector<SPMemTest> m_SPMemTest;

SPMemTest sp1 = SPMemTest(new CMemTest);
m_SPMemTest.push_back(sp1);
m_SPMemTest.push_back(sp1);
m_SPMemTest.pop_back();
m_SPMemTest.pop_back();

//이렇게 하면 삭제가 됩니다.
//다른 방법으로 사용하면 아래도 가능하죠
m_SPMemTest.push_back(SPMemTest(new CMemTest(10)));
m_SPMemTest.push_back(SPMemTest(new CMemTest));

//값을 사용할때
. 가 아니고 -> 를 사용해야 합니다.
m_SPMemTest[0]->_val = 10;

//erase와 clear만 사용하면 자동으로 메모리 삭제 됨

count = m_SPMemTest.size();
m_SPMemTest.erase(m_SPMemTest.begin());
count = m_SPMemTest.size();

m_SPMemTest.clear();

Posted by gsi
:

stl 문중에서 아마도 vector를 가장 개인적으로 선호 한다.
이론적인 내용은 우선 접어 두고.. (책을 보면 안다 ^^)

기존에 내가 했던 작업은 vector와 for문을 많이 사용했다.
이번에 accumulate, for_each를 공부 하면서 많은 부분 간소화 시키고
가독성과 범용성을 갖출수 있는 방법을 찾아 봤다.
class 의 객체를 vector에 추가 해서 작업 할때 vector의 배열 정보를 사용해서
특정 변수의 값을 다르게 변경할 작업이 많이 생긴다.

//헤더에 필요한 헤더파일을 추가한다.

#include <vector>
#include <map>
#include <algorithm>
#include <numeric>

using namespace std;

아래와 같은 클래스가 있다고 하자.

class Element {
public:
 DWORD UID;
 INT  Price;
 int  Count;
 DWORD Res_ID;

 //생성자
 Element(DWORD uid, INT price, int count, DWORD res_id, ) :
  UID(uid),
  Price(price),
  Count(count),
  Res_ID(res_id),
 {
 }

 //operator
 bool operator==(const Element& e) const {
  return (UID == e.UID) ? true : false;
 }
};

위의 코드에서 price는 가격을 뜻하고, count는 수량을 뜻한다.
Res_ID는 해당 오브젝트의 리소스 아이디라고 가정을 하자.
아래와 같은 작업을 할려고 한다.

1. Count가 음수인 요소들의 개수를 얻어 오고 싶다.
2. Count가 음수인 요소들의 Price의 총 합을 얻고 싶다.
3. Count가 음수인 요소들의 Res_ID의 목록을 얻고 싶다.

기존에 for문을 사용하게 되면 코드의 량도 늘어 나고 보기에도 좀 그렇다.
아래와 같은 accumulate 함수를 작성하고 활용하면 자연스럽게 구현이 가능하다.

//카운터가 0보다 작은 요소들의 개수
int count_minus_element_sum (int count, const Element& t1 ) {
 if(t1.Count < 0)
  count++;

 return count;
}

//카운터가 0보다 작은 요소들의 총금액
int count_minus_element_price_sum (int price, const Element& t1 )
{
 if(t1.Count < 0) {
  price += (abs(t1.Count) * t1.Price);
 }

 return price;
}

//카운터가 0보다 작은 resid를 추출
vector<DWORD>& count_minus_resid ( vector<DWORD>& v, const Element& t1 )
{
 if(t1.Count < 0) {
  v.push_back(t1.Res_ID);
 }
 return v;
}

//for_each - cout << resid << endl
void display_resid ( const DWORD& ri )
{
 cout << ri << endl;
}

//벡터 테스트
 vector< Element > m_ElementList;

//요소를 추가한다.

 m_ElementList.push_back(Element(100, 100, 1, 2000));
 m_ElementList.push_back(Element(101, 100, 2, 2001));
 m_ElementList.push_back(Element(102, 100, 3, 2002));
 m_ElementList.push_back(Element(103, 100, -1, 2003));
 m_ElementList.push_back(Element(104, 100, 0, 2004));
 m_ElementList.push_back(Element(105, 100, -2, 2005));
 m_ElementList.push_back(Element(106, 100, -3, 2006));
 m_ElementList.push_back(Element(107, 100, -1, 2007));
 m_ElementList.push_back(Element(108, 100, 2, 2008));
 m_ElementList.push_back(Element(109, 100, 3, 2009));
 m_ElementList.push_back(Element(110, 100, 6, 2010));

//음수인 요소의 개수의 총 합을 구한다.

 int count = accumulate(m_ElementList.begin(), m_ElementList.end(), 0, count_minus_element_sum);

//음수인 요소의 가격의 총 합을 구한다.
 int price = accumulate(m_ElementList.begin(), m_ElementList.end(), 0, count_minus_element_price_sum);

//음수인 요소의 Res_ID의 목록을 구한다.
 vector<DWORD> m_ResID; //목록을 담을 배열을 선언한다.
 m_ResID.clear(); //클리어
 m_ResID = accumulate(m_ElementList.begin(), m_ElementList.end(), m_ResID, count_minus_resid);

//담겨진 요소의 Res_ID를 화면에 출력해 본다.

 for_each(m_ResID.begin(), m_ResID.end(), display_resid);

위와 같이 accumulator를 잘만 사용하면 아주 다양한 효과를 볼 수 있을거 같다.
총 합을 구하거나 모든 요소의 특징을 살펴 본다거나 하는 형태의 작업에 아주 탁월하다.

for_each는 for문을 사용하는 번거로움을 조금 해소해 줄수 있다.

Posted by gsi
: